pyerrors.input.openQCD
1import os 2import fnmatch 3import re 4import struct 5import warnings 6import numpy as np # Thinly-wrapped numpy 7import matplotlib.pyplot as plt 8from matplotlib import gridspec 9from ..obs import Obs 10from ..fits import fit_lin 11 12 13def read_rwms(path, prefix, version='2.0', names=None, **kwargs): 14 """Read rwms format from given folder structure. Returns a list of length nrw 15 16 Parameters 17 ---------- 18 path : str 19 path that contains the data files 20 prefix : str 21 all files in path that start with prefix are considered as input files. 22 May be used together postfix to consider only special file endings. 23 Prefix is ignored, if the keyword 'files' is used. 24 version : str 25 version of openQCD, default 2.0 26 names : list 27 list of names that is assigned to the data according according 28 to the order in the file list. Use careful, if you do not provide file names! 29 r_start : list 30 list which contains the first config to be read for each replicum 31 r_stop : list 32 list which contains the last config to be read for each replicum 33 r_step : int 34 integer that defines a fixed step size between two measurements (in units of configs) 35 If not given, r_step=1 is assumed. 36 postfix : str 37 postfix of the file to read, e.g. '.ms1' for openQCD-files 38 files : list 39 list which contains the filenames to be read. No automatic detection of 40 files performed if given. 41 print_err : bool 42 Print additional information that is useful for debugging. 43 """ 44 known_oqcd_versions = ['1.4', '1.6', '2.0'] 45 if not (version in known_oqcd_versions): 46 raise Exception('Unknown openQCD version defined!') 47 print("Working with openQCD version " + version) 48 if 'postfix' in kwargs: 49 postfix = kwargs.get('postfix') 50 else: 51 postfix = '' 52 ls = [] 53 for (dirpath, dirnames, filenames) in os.walk(path): 54 ls.extend(filenames) 55 break 56 57 if not ls: 58 raise Exception('Error, directory not found') 59 if 'files' in kwargs: 60 ls = kwargs.get('files') 61 else: 62 for exc in ls: 63 if not fnmatch.fnmatch(exc, prefix + '*' + postfix + '.dat'): 64 ls = list(set(ls) - set([exc])) 65 if len(ls) > 1: 66 ls.sort(key=lambda x: int(re.findall(r'\d+', x[len(prefix):])[0])) 67 replica = len(ls) 68 69 if 'r_start' in kwargs: 70 r_start = kwargs.get('r_start') 71 if len(r_start) != replica: 72 raise Exception('r_start does not match number of replicas') 73 r_start = [o if o else None for o in r_start] 74 else: 75 r_start = [None] * replica 76 77 if 'r_stop' in kwargs: 78 r_stop = kwargs.get('r_stop') 79 if len(r_stop) != replica: 80 raise Exception('r_stop does not match number of replicas') 81 else: 82 r_stop = [None] * replica 83 84 if 'r_step' in kwargs: 85 r_step = kwargs.get('r_step') 86 else: 87 r_step = 1 88 89 print('Read reweighting factors from', prefix[:-1], ',', 90 replica, 'replica', end='') 91 92 if names is None: 93 rep_names = [] 94 for entry in ls: 95 truncated_entry = entry 96 suffixes = [".dat", ".rwms", ".ms1"] 97 for suffix in suffixes: 98 if truncated_entry.endswith(suffix): 99 truncated_entry = truncated_entry[0:-len(suffix)] 100 idx = truncated_entry.index('r') 101 rep_names.append(truncated_entry[:idx] + '|' + truncated_entry[idx:]) 102 else: 103 rep_names = names 104 105 print_err = 0 106 if 'print_err' in kwargs: 107 print_err = 1 108 print() 109 110 deltas = [] 111 112 configlist = [] 113 r_start_index = [] 114 r_stop_index = [] 115 116 for rep in range(replica): 117 tmp_array = [] 118 with open(path + '/' + ls[rep], 'rb') as fp: 119 120 t = fp.read(4) # number of reweighting factors 121 if rep == 0: 122 nrw = struct.unpack('i', t)[0] 123 if version == '2.0': 124 nrw = int(nrw / 2) 125 for k in range(nrw): 126 deltas.append([]) 127 else: 128 if ((nrw != struct.unpack('i', t)[0] and (not version == '2.0')) or (nrw != struct.unpack('i', t)[0] / 2 and version == '2.0')): 129 raise Exception('Error: different number of reweighting factors for replicum', rep) 130 131 for k in range(nrw): 132 tmp_array.append([]) 133 134 # This block is necessary for openQCD1.6 and openQCD2.0 ms1 files 135 nfct = [] 136 if version in ['1.6', '2.0']: 137 for i in range(nrw): 138 t = fp.read(4) 139 nfct.append(struct.unpack('i', t)[0]) 140 else: 141 for i in range(nrw): 142 nfct.append(1) 143 144 nsrc = [] 145 for i in range(nrw): 146 t = fp.read(4) 147 nsrc.append(struct.unpack('i', t)[0]) 148 if version == '2.0': 149 if not struct.unpack('i', fp.read(4))[0] == 0: 150 print('something is wrong!') 151 152 configlist.append([]) 153 while 0 < 1: 154 t = fp.read(4) 155 if len(t) < 4: 156 break 157 config_no = struct.unpack('i', t)[0] 158 configlist[-1].append(config_no) 159 for i in range(nrw): 160 if(version == '2.0'): 161 tmpd = _read_array_openQCD2(fp) 162 tmpd = _read_array_openQCD2(fp) 163 tmp_rw = tmpd['arr'] 164 tmp_nfct = 1.0 165 for j in range(tmpd['n'][0]): 166 tmp_nfct *= np.mean(np.exp(-np.asarray(tmp_rw[j]))) 167 if print_err: 168 print(config_no, i, j, 169 np.mean(np.exp(-np.asarray(tmp_rw[j]))), 170 np.std(np.exp(-np.asarray(tmp_rw[j])))) 171 print('Sources:', 172 np.exp(-np.asarray(tmp_rw[j]))) 173 print('Partial factor:', tmp_nfct) 174 elif version == '1.6' or version == '1.4': 175 tmp_nfct = 1.0 176 for j in range(nfct[i]): 177 t = fp.read(8 * nsrc[i]) 178 t = fp.read(8 * nsrc[i]) 179 tmp_rw = struct.unpack('d' * nsrc[i], t) 180 tmp_nfct *= np.mean(np.exp(-np.asarray(tmp_rw))) 181 if print_err: 182 print(config_no, i, j, 183 np.mean(np.exp(-np.asarray(tmp_rw))), 184 np.std(np.exp(-np.asarray(tmp_rw)))) 185 print('Sources:', np.exp(-np.asarray(tmp_rw))) 186 print('Partial factor:', tmp_nfct) 187 tmp_array[i].append(tmp_nfct) 188 189 diffmeas = configlist[-1][-1] - configlist[-1][-2] 190 configlist[-1] = [item // diffmeas for item in configlist[-1]] 191 if configlist[-1][0] > 1 and diffmeas > 1: 192 warnings.warn('Assume thermalization and that the first measurement belongs to the first config.') 193 offset = configlist[-1][0] - 1 194 configlist[-1] = [item - offset for item in configlist[-1]] 195 196 if r_start[rep] is None: 197 r_start_index.append(0) 198 else: 199 try: 200 r_start_index.append(configlist[-1].index(r_start[rep])) 201 except ValueError: 202 raise Exception('Config %d not in file with range [%d, %d]' % ( 203 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None 204 205 if r_stop[rep] is None: 206 r_stop_index.append(len(configlist[-1]) - 1) 207 else: 208 try: 209 r_stop_index.append(configlist[-1].index(r_stop[rep])) 210 except ValueError: 211 raise Exception('Config %d not in file with range [%d, %d]' % ( 212 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None 213 214 for k in range(nrw): 215 deltas[k].append(tmp_array[k][r_start_index[rep]:r_stop_index[rep] + 1][::r_step]) 216 217 if np.any([len(np.unique(np.diff(cl))) != 1 for cl in configlist]): 218 raise Exception('Irregular spaced data in input file!', [len(np.unique(np.diff(cl))) for cl in configlist]) 219 stepsizes = [list(np.unique(np.diff(cl)))[0] for cl in configlist] 220 if np.any([step != 1 for step in stepsizes]): 221 warnings.warn('Stepsize between configurations is greater than one!' + str(stepsizes), RuntimeWarning) 222 223 print(',', nrw, 'reweighting factors with', nsrc, 'sources') 224 result = [] 225 idl = [range(configlist[rep][r_start_index[rep]], configlist[rep][r_stop_index[rep]] + 1, r_step) for rep in range(replica)] 226 227 for t in range(nrw): 228 result.append(Obs(deltas[t], rep_names, idl=idl)) 229 return result 230 231 232def extract_t0(path, prefix, dtr_read, xmin, spatial_extent, fit_range=5, **kwargs): 233 """Extract t0 from given .ms.dat files. Returns t0 as Obs. 234 235 It is assumed that all boundary effects have 236 sufficiently decayed at x0=xmin. 237 The data around the zero crossing of t^2<E> - 0.3 238 is fitted with a linear function 239 from which the exact root is extracted. 240 241 It is assumed that one measurement is performed for each config. 242 If this is not the case, the resulting idl, as well as the handling 243 of r_start, r_stop and r_step is wrong and the user has to correct 244 this in the resulting observable. 245 246 Parameters 247 ---------- 248 path : str 249 Path to .ms.dat files 250 prefix : str 251 Ensemble prefix 252 dtr_read : int 253 Determines how many trajectories should be skipped 254 when reading the ms.dat files. 255 Corresponds to dtr_cnfg / dtr_ms in the openQCD input file. 256 xmin : int 257 First timeslice where the boundary 258 effects have sufficiently decayed. 259 spatial_extent : int 260 spatial extent of the lattice, required for normalization. 261 fit_range : int 262 Number of data points left and right of the zero 263 crossing to be included in the linear fit. (Default: 5) 264 r_start : list 265 list which contains the first config to be read for each replicum. 266 r_stop : list 267 list which contains the last config to be read for each replicum. 268 r_step : int 269 integer that defines a fixed step size between two measurements (in units of configs) 270 If not given, r_step=1 is assumed. 271 plaquette : bool 272 If true extract the plaquette estimate of t0 instead. 273 names : list 274 list of names that is assigned to the data according according 275 to the order in the file list. Use careful, if you do not provide file names! 276 files : list 277 list which contains the filenames to be read. No automatic detection of 278 files performed if given. 279 plot_fit : bool 280 If true, the fit for the extraction of t0 is shown together with the data. 281 assume_thermalization : bool 282 If True: If the first record divided by the distance between two measurements is larger than 283 1, it is assumed that this is due to thermalization and the first measurement belongs 284 to the first config (default). 285 If False: The config numbers are assumed to be traj_number // difference 286 """ 287 288 ls = [] 289 for (dirpath, dirnames, filenames) in os.walk(path): 290 ls.extend(filenames) 291 break 292 293 if not ls: 294 raise Exception('Error, directory not found') 295 296 if 'files' in kwargs: 297 ls = kwargs.get('files') 298 else: 299 for exc in ls: 300 if not fnmatch.fnmatch(exc, prefix + '*.ms.dat'): 301 ls = list(set(ls) - set([exc])) 302 if len(ls) > 1: 303 ls.sort(key=lambda x: int(re.findall(r'\d+', x[len(prefix):])[0])) 304 replica = len(ls) 305 306 if 'r_start' in kwargs: 307 r_start = kwargs.get('r_start') 308 if len(r_start) != replica: 309 raise Exception('r_start does not match number of replicas') 310 r_start = [o if o else None for o in r_start] 311 else: 312 r_start = [None] * replica 313 314 if 'r_stop' in kwargs: 315 r_stop = kwargs.get('r_stop') 316 if len(r_stop) != replica: 317 raise Exception('r_stop does not match number of replicas') 318 else: 319 r_stop = [None] * replica 320 321 if 'r_step' in kwargs: 322 r_step = kwargs.get('r_step') 323 else: 324 r_step = 1 325 326 print('Extract t0 from', prefix, ',', replica, 'replica') 327 328 if 'names' in kwargs: 329 rep_names = kwargs.get('names') 330 else: 331 rep_names = [] 332 for entry in ls: 333 truncated_entry = entry.split('.')[0] 334 idx = truncated_entry.index('r') 335 rep_names.append(truncated_entry[:idx] + '|' + truncated_entry[idx:]) 336 337 Ysum = [] 338 339 configlist = [] 340 r_start_index = [] 341 r_stop_index = [] 342 343 for rep in range(replica): 344 345 with open(path + '/' + ls[rep], 'rb') as fp: 346 t = fp.read(12) 347 header = struct.unpack('iii', t) 348 if rep == 0: 349 dn = header[0] 350 nn = header[1] 351 tmax = header[2] 352 elif dn != header[0] or nn != header[1] or tmax != header[2]: 353 raise Exception('Replica parameters do not match.') 354 355 t = fp.read(8) 356 if rep == 0: 357 eps = struct.unpack('d', t)[0] 358 print('Step size:', eps, ', Maximal t value:', dn * (nn) * eps) 359 elif eps != struct.unpack('d', t)[0]: 360 raise Exception('Values for eps do not match among replica.') 361 362 Ysl = [] 363 364 configlist.append([]) 365 while 0 < 1: 366 t = fp.read(4) 367 if(len(t) < 4): 368 break 369 nc = struct.unpack('i', t)[0] 370 configlist[-1].append(nc) 371 372 t = fp.read(8 * tmax * (nn + 1)) 373 if kwargs.get('plaquette'): 374 if nc % dtr_read == 0: 375 Ysl.append(struct.unpack('d' * tmax * (nn + 1), t)) 376 t = fp.read(8 * tmax * (nn + 1)) 377 if not kwargs.get('plaquette'): 378 if nc % dtr_read == 0: 379 Ysl.append(struct.unpack('d' * tmax * (nn + 1), t)) 380 t = fp.read(8 * tmax * (nn + 1)) 381 382 Ysum.append([]) 383 for i, item in enumerate(Ysl): 384 Ysum[-1].append([np.mean(item[current + xmin: 385 current + tmax - xmin]) 386 for current in range(0, len(item), tmax)]) 387 388 diffmeas = configlist[-1][-1] - configlist[-1][-2] 389 configlist[-1] = [item // diffmeas for item in configlist[-1]] 390 if kwargs.get('assume_thermalization', True) and configlist[-1][0] > 1: 391 warnings.warn('Assume thermalization and that the first measurement belongs to the first config.') 392 offset = configlist[-1][0] - 1 393 configlist[-1] = [item - offset for item in configlist[-1]] 394 395 if r_start[rep] is None: 396 r_start_index.append(0) 397 else: 398 try: 399 r_start_index.append(configlist[-1].index(r_start[rep])) 400 except ValueError: 401 raise Exception('Config %d not in file with range [%d, %d]' % ( 402 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None 403 404 if r_stop[rep] is None: 405 r_stop_index.append(len(configlist[-1]) - 1) 406 else: 407 try: 408 r_stop_index.append(configlist[-1].index(r_stop[rep])) 409 except ValueError: 410 raise Exception('Config %d not in file with range [%d, %d]' % ( 411 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None 412 413 if np.any([len(np.unique(np.diff(cl))) != 1 for cl in configlist]): 414 raise Exception('Irregular spaced data in input file!', [len(np.unique(np.diff(cl))) for cl in configlist]) 415 stepsizes = [list(np.unique(np.diff(cl)))[0] for cl in configlist] 416 if np.any([step != 1 for step in stepsizes]): 417 warnings.warn('Stepsize between configurations is greater than one!' + str(stepsizes), RuntimeWarning) 418 419 idl = [range(configlist[rep][r_start_index[rep]], configlist[rep][r_stop_index[rep]] + 1, r_step) for rep in range(replica)] 420 t2E_dict = {} 421 for n in range(nn + 1): 422 samples = [] 423 for nrep, rep in enumerate(Ysum): 424 samples.append([]) 425 for cnfg in rep: 426 samples[-1].append(cnfg[n]) 427 samples[-1] = samples[-1][r_start_index[nrep]:r_stop_index[nrep] + 1][::r_step] 428 new_obs = Obs(samples, rep_names, idl=idl) 429 t2E_dict[n * dn * eps] = (n * dn * eps) ** 2 * new_obs / (spatial_extent ** 3) - 0.3 430 431 zero_crossing = np.argmax(np.array( 432 [o.value for o in t2E_dict.values()]) > 0.0) 433 434 x = list(t2E_dict.keys())[zero_crossing - fit_range: 435 zero_crossing + fit_range] 436 y = list(t2E_dict.values())[zero_crossing - fit_range: 437 zero_crossing + fit_range] 438 [o.gamma_method() for o in y] 439 440 fit_result = fit_lin(x, y) 441 442 if kwargs.get('plot_fit'): 443 plt.figure() 444 gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1], wspace=0.0, hspace=0.0) 445 ax0 = plt.subplot(gs[0]) 446 xmore = list(t2E_dict.keys())[zero_crossing - fit_range - 2: zero_crossing + fit_range + 2] 447 ymore = list(t2E_dict.values())[zero_crossing - fit_range - 2: zero_crossing + fit_range + 2] 448 [o.gamma_method() for o in ymore] 449 ax0.errorbar(xmore, [yi.value for yi in ymore], yerr=[yi.dvalue for yi in ymore], fmt='x') 450 xplot = np.linspace(np.min(x), np.max(x)) 451 yplot = [fit_result[0] + fit_result[1] * xi for xi in xplot] 452 [yi.gamma_method() for yi in yplot] 453 ax0.fill_between(xplot, y1=[yi.value - yi.dvalue for yi in yplot], y2=[yi.value + yi.dvalue for yi in yplot]) 454 retval = (-fit_result[0] / fit_result[1]) 455 retval.gamma_method() 456 ylim = ax0.get_ylim() 457 ax0.fill_betweenx(ylim, x1=retval.value - retval.dvalue, x2=retval.value + retval.dvalue, color='gray', alpha=0.4) 458 ax0.set_ylim(ylim) 459 ax0.set_ylabel(r'$t^2 \langle E(t) \rangle - 0.3 $') 460 xlim = ax0.get_xlim() 461 462 fit_res = [fit_result[0] + fit_result[1] * xi for xi in x] 463 residuals = (np.asarray([o.value for o in y]) - [o.value for o in fit_res]) / np.asarray([o.dvalue for o in y]) 464 ax1 = plt.subplot(gs[1]) 465 ax1.plot(x, residuals, 'ko', ls='none', markersize=5) 466 ax1.tick_params(direction='out') 467 ax1.tick_params(axis="x", bottom=True, top=True, labelbottom=True) 468 ax1.axhline(y=0.0, ls='--', color='k') 469 ax1.fill_between(xlim, -1.0, 1.0, alpha=0.1, facecolor='k') 470 ax1.set_xlim(xlim) 471 ax1.set_ylabel('Residuals') 472 ax1.set_xlabel(r'$t/a^2$') 473 474 plt.draw() 475 return -fit_result[0] / fit_result[1] 476 477 478def _parse_array_openQCD2(d, n, size, wa, quadrupel=False): 479 arr = [] 480 if d == 2: 481 for i in range(n[0]): 482 tmp = wa[i * n[1]:(i + 1) * n[1]] 483 if quadrupel: 484 tmp2 = [] 485 for j in range(0, len(tmp), 2): 486 tmp2.append(tmp[j]) 487 arr.append(tmp2) 488 else: 489 arr.append(np.asarray(tmp)) 490 491 else: 492 raise Exception('Only two-dimensional arrays supported!') 493 494 return arr 495 496 497def _read_array_openQCD2(fp): 498 t = fp.read(4) 499 d = struct.unpack('i', t)[0] 500 t = fp.read(4 * d) 501 n = struct.unpack('%di' % (d), t) 502 t = fp.read(4) 503 size = struct.unpack('i', t)[0] 504 if size == 4: 505 types = 'i' 506 elif size == 8: 507 types = 'd' 508 elif size == 16: 509 types = 'dd' 510 else: 511 raise Exception("Type for size '" + str(size) + "' not known.") 512 m = n[0] 513 for i in range(1, d): 514 m *= n[i] 515 516 t = fp.read(m * size) 517 tmp = struct.unpack('%d%s' % (m, types), t) 518 519 arr = _parse_array_openQCD2(d, n, size, tmp, quadrupel=True) 520 return {'d': d, 'n': n, 'size': size, 'arr': arr} 521 522 523def read_qtop(path, prefix, c, dtr_cnfg=1, version="openQCD", **kwargs): 524 """Read the topologial charge based on openQCD gradient flow measurements. 525 526 Parameters 527 ---------- 528 path : str 529 path of the measurement files 530 prefix : str 531 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat. 532 Ignored if file names are passed explicitly via keyword files. 533 c : double 534 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L. 535 dtr_cnfg : int 536 (optional) parameter that specifies the number of measurements 537 between two configs. 538 If it is not set, the distance between two measurements 539 in the file is assumed to be the distance between two configurations. 540 steps : int 541 (optional) Distance between two configurations in units of trajectories / 542 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given 543 version : str 544 Either openQCD or sfqcd, depending on the data. 545 L : int 546 spatial length of the lattice in L/a. 547 HAS to be set if version != sfqcd, since openQCD does not provide 548 this in the header 549 r_start : list 550 list which contains the first config to be read for each replicum. 551 r_stop : list 552 list which contains the last config to be read for each replicum. 553 files : list 554 specify the exact files that need to be read 555 from path, practical if e.g. only one replicum is needed 556 names : list 557 Alternative labeling for replicas/ensembles. 558 Has to have the appropriate length. 559 Zeuthen_flow : bool 560 (optional) If True, the Zeuthen flow is used for Qtop. Only possible 561 for version=='sfqcd' If False, the Wilson flow is used. 562 integer_charge : bool 563 If True, the charge is rounded towards the nearest integer on each config. 564 """ 565 known_versions = ["openQCD", "sfqcd"] 566 567 if version not in known_versions: 568 raise Exception("Unknown openQCD version.") 569 if "steps" in kwargs: 570 steps = kwargs.get("steps") 571 if version == "sfqcd": 572 if "L" in kwargs: 573 supposed_L = kwargs.get("L") 574 else: 575 supposed_L = None 576 postfix = ".gfms.dat" 577 else: 578 if "L" not in kwargs: 579 raise Exception("This version of openQCD needs you to provide the spatial length of the lattice as parameter 'L'.") 580 else: 581 L = kwargs.get("L") 582 postfix = ".ms.dat" 583 584 if "files" in kwargs: 585 files = kwargs.get("files") 586 postfix = '' 587 else: 588 found = [] 589 files = [] 590 for (dirpath, dirnames, filenames) in os.walk(path + "/"): 591 found.extend(filenames) 592 break 593 for f in found: 594 if fnmatch.fnmatch(f, prefix + "*" + postfix): 595 files.append(f) 596 597 if 'r_start' in kwargs: 598 r_start = kwargs.get('r_start') 599 if len(r_start) != len(files): 600 raise Exception('r_start does not match number of replicas') 601 r_start = [o if o else None for o in r_start] 602 else: 603 r_start = [None] * len(files) 604 605 if 'r_stop' in kwargs: 606 r_stop = kwargs.get('r_stop') 607 if len(r_stop) != len(files): 608 raise Exception('r_stop does not match number of replicas') 609 else: 610 r_stop = [None] * len(files) 611 rep_names = [] 612 613 zeuthen = kwargs.get('Zeuthen_flow', False) 614 if zeuthen and version not in ['sfqcd']: 615 raise Exception('Zeuthen flow can only be used for version==sfqcd') 616 617 r_start_index = [] 618 r_stop_index = [] 619 deltas = [] 620 configlist = [] 621 for rep, file in enumerate(files): 622 with open(path + "/" + file, "rb") as fp: 623 624 Q = [] 625 traj_list = [] 626 if version in ['sfqcd']: 627 if zeuthen: 628 obspos = 0 629 else: 630 obspos = 8 631 t = fp.read(12) 632 header = struct.unpack('<iii', t) 633 zthfl = header[0] # Zeuthen flow -> if it's equal to 2 it means that the Zeuthen flow is also 'measured' (apart from the Wilson flow) 634 ncs = header[1] # number of different values for c in t_flow=1/8 c² L² -> measurements done for ncs c's 635 tmax = header[2] # lattice T/a 636 637 t = fp.read(12) 638 Ls = struct.unpack('<iii', t) 639 if(Ls[0] == Ls[1] and Ls[1] == Ls[2]): 640 L = Ls[0] 641 if not (supposed_L == L) and supposed_L: 642 raise Exception("It seems the length given in the header and by you contradict each other") 643 else: 644 raise Exception("Found more than one spatial length in header!") 645 646 t = fp.read(16) 647 header2 = struct.unpack('<dd', t) 648 tol = header2[0] 649 cmax = header2[1] # highest value of c used 650 651 if c > cmax: 652 raise Exception('Flow has been determined between c=0 and c=%lf with tolerance %lf' % (cmax, tol)) 653 654 if(zthfl == 2): 655 nfl = 2 # number of flows 656 else: 657 nfl = 1 658 iobs = 8 * nfl # number of flow observables calculated 659 660 while 0 < 1: 661 t = fp.read(4) 662 if(len(t) < 4): 663 break 664 traj_list.append(struct.unpack('i', t)[0]) # trajectory number when measurement was done 665 666 for j in range(ncs + 1): 667 for i in range(iobs): 668 t = fp.read(8 * tmax) 669 if (i == obspos): # determines the flow observable -> i=0 <-> Zeuthen flow 670 Q.append(struct.unpack('d' * tmax, t)) 671 672 else: 673 t = fp.read(12) 674 header = struct.unpack('<iii', t) 675 # step size in integration steps "dnms" 676 dn = header[0] 677 # number of measurements, so "ntot"/dn 678 nn = header[1] 679 # lattice T/a 680 tmax = header[2] 681 682 t = fp.read(8) 683 eps = struct.unpack('d', t)[0] 684 685 while 0 < 1: 686 t = fp.read(4) 687 if(len(t) < 4): 688 break 689 traj_list.append(struct.unpack('i', t)[0]) 690 # Wsl 691 t = fp.read(8 * tmax * (nn + 1)) 692 # Ysl 693 t = fp.read(8 * tmax * (nn + 1)) 694 # Qsl, which is asked for in this method 695 t = fp.read(8 * tmax * (nn + 1)) 696 # unpack the array of Qtops, 697 # on each timeslice t=0,...,tmax-1 and the 698 # measurement number in = 0...nn (see README.qcd1) 699 tmpd = struct.unpack('d' * tmax * (nn + 1), t) 700 Q.append(tmpd) 701 702 if len(np.unique(np.diff(traj_list))) != 1: 703 raise Exception("Irregularities in stepsize found") 704 else: 705 if 'steps' in kwargs: 706 if steps != traj_list[1] - traj_list[0]: 707 raise Exception("steps and the found stepsize are not the same") 708 else: 709 steps = traj_list[1] - traj_list[0] 710 711 configlist.append([tr // steps // dtr_cnfg for tr in traj_list]) 712 if configlist[-1][0] > 1: 713 offset = configlist[-1][0] - 1 714 warnings.warn('Assume thermalization and that the first measurement belongs to the first config. Offset = %d configs (%d trajectories / cycles)' % ( 715 offset, offset * steps)) 716 configlist[-1] = [item - offset for item in configlist[-1]] 717 718 if r_start[rep] is None: 719 r_start_index.append(0) 720 else: 721 try: 722 r_start_index.append(configlist[-1].index(r_start[rep])) 723 except ValueError: 724 raise Exception('Config %d not in file with range [%d, %d]' % ( 725 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None 726 727 if r_stop[rep] is None: 728 r_stop_index.append(len(configlist[-1]) - 1) 729 else: 730 try: 731 r_stop_index.append(configlist[-1].index(r_stop[rep])) 732 except ValueError: 733 raise Exception('Config %d not in file with range [%d, %d]' % ( 734 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None 735 736 if version in ['sfqcd']: 737 cstepsize = cmax / ncs 738 index_aim = round(c / cstepsize) 739 else: 740 t_aim = (c * L) ** 2 / 8 741 index_aim = round(t_aim / eps / dn) 742 743 Q_sum = [] 744 for i, item in enumerate(Q): 745 Q_sum.append([sum(item[current:current + tmax]) 746 for current in range(0, len(item), tmax)]) 747 Q_top = [] 748 if version in ['sfqcd']: 749 for i in range(len(Q_sum) // (ncs + 1)): 750 Q_top.append(Q_sum[i * (ncs + 1) + index_aim][0]) 751 else: 752 for i in range(len(Q) // dtr_cnfg): 753 Q_top.append(Q_sum[dtr_cnfg * i][index_aim]) 754 if len(Q_top) != len(traj_list) // dtr_cnfg: 755 raise Exception("qtops and traj_list dont have the same length") 756 757 if kwargs.get('integer_charge', False): 758 Q_top = [round(q) for q in Q_top] 759 760 truncated_file = file[:-len(postfix)] 761 762 if "names" not in kwargs: 763 try: 764 idx = truncated_file.index('r') 765 except Exception: 766 if "names" not in kwargs: 767 raise Exception("Automatic recognition of replicum failed, please enter the key word 'names'.") 768 ens_name = truncated_file[:idx] 769 rep_names.append(ens_name + '|' + truncated_file[idx:]) 770 else: 771 names = kwargs.get("names") 772 rep_names = names 773 deltas.append(Q_top) 774 775 idl = [range(int(configlist[rep][r_start_index[rep]]), int(configlist[rep][r_stop_index[rep]]) + 1, 1) for rep in range(len(deltas))] 776 deltas = [deltas[nrep][r_start_index[nrep]:r_stop_index[nrep] + 1] for nrep in range(len(deltas))] 777 result = Obs(deltas, rep_names, idl=idl) 778 return result 779 780 781def qtop_projection(qtop, target=0): 782 """Returns the projection to the topological charge sector defined by target. 783 784 Parameters 785 ---------- 786 path : Obs 787 Topological charge. 788 target : int 789 Specifies the topological sector to be reweighted to (default 0) 790 """ 791 if qtop.reweighted: 792 raise Exception('You can not use a reweighted observable for reweighting!') 793 794 proj_qtop = [] 795 for n in qtop.deltas: 796 proj_qtop.append(np.array([1 if round(qtop.value + q) == target else 0 for q in qtop.deltas[n]])) 797 798 reto = Obs(proj_qtop, qtop.names, idl=[qtop.idl[name] for name in qtop.names]) 799 reto.is_merged = qtop.is_merged 800 return reto 801 802 803def read_qtop_sector(path, prefix, c, target=0, **kwargs): 804 """Constructs reweighting factors to a specified topological sector. 805 806 Parameters 807 ---------- 808 path : str 809 path of the measurement files 810 prefix : str 811 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat 812 c : double 813 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L 814 target : int 815 Specifies the topological sector to be reweighted to (default 0) 816 dtr_cnfg : int 817 (optional) parameter that specifies the number of trajectories 818 between two configs. 819 if it is not set, the distance between two measurements 820 in the file is assumed to be the distance between two configurations. 821 steps : int 822 (optional) Distance between two configurations in units of trajectories / 823 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given 824 version : str 825 version string of the openQCD (sfqcd) version used to create 826 the ensemble. Default is 2.0. May also be set to sfqcd. 827 L : int 828 spatial length of the lattice in L/a. 829 HAS to be set if version != sfqcd, since openQCD does not provide 830 this in the header 831 r_start : list 832 offset of the first ensemble, making it easier to match 833 later on with other Obs 834 r_stop : list 835 last configurations that need to be read (per replicum) 836 files : list 837 specify the exact files that need to be read 838 from path, practical if e.g. only one replicum is needed 839 names : list 840 Alternative labeling for replicas/ensembles. 841 Has to have the appropriate length 842 Zeuthen_flow : bool 843 (optional) If True, the Zeuthen flow is used for Qtop. Only possible 844 for version=='sfqcd' If False, the Wilson flow is used. 845 """ 846 847 if not isinstance(target, int): 848 raise Exception("'target' has to be an integer.") 849 850 kwargs['integer_charge'] = True 851 qtop = read_qtop(path, prefix, c, **kwargs) 852 853 return qtop_projection(qtop, target=target)
14def read_rwms(path, prefix, version='2.0', names=None, **kwargs): 15 """Read rwms format from given folder structure. Returns a list of length nrw 16 17 Parameters 18 ---------- 19 path : str 20 path that contains the data files 21 prefix : str 22 all files in path that start with prefix are considered as input files. 23 May be used together postfix to consider only special file endings. 24 Prefix is ignored, if the keyword 'files' is used. 25 version : str 26 version of openQCD, default 2.0 27 names : list 28 list of names that is assigned to the data according according 29 to the order in the file list. Use careful, if you do not provide file names! 30 r_start : list 31 list which contains the first config to be read for each replicum 32 r_stop : list 33 list which contains the last config to be read for each replicum 34 r_step : int 35 integer that defines a fixed step size between two measurements (in units of configs) 36 If not given, r_step=1 is assumed. 37 postfix : str 38 postfix of the file to read, e.g. '.ms1' for openQCD-files 39 files : list 40 list which contains the filenames to be read. No automatic detection of 41 files performed if given. 42 print_err : bool 43 Print additional information that is useful for debugging. 44 """ 45 known_oqcd_versions = ['1.4', '1.6', '2.0'] 46 if not (version in known_oqcd_versions): 47 raise Exception('Unknown openQCD version defined!') 48 print("Working with openQCD version " + version) 49 if 'postfix' in kwargs: 50 postfix = kwargs.get('postfix') 51 else: 52 postfix = '' 53 ls = [] 54 for (dirpath, dirnames, filenames) in os.walk(path): 55 ls.extend(filenames) 56 break 57 58 if not ls: 59 raise Exception('Error, directory not found') 60 if 'files' in kwargs: 61 ls = kwargs.get('files') 62 else: 63 for exc in ls: 64 if not fnmatch.fnmatch(exc, prefix + '*' + postfix + '.dat'): 65 ls = list(set(ls) - set([exc])) 66 if len(ls) > 1: 67 ls.sort(key=lambda x: int(re.findall(r'\d+', x[len(prefix):])[0])) 68 replica = len(ls) 69 70 if 'r_start' in kwargs: 71 r_start = kwargs.get('r_start') 72 if len(r_start) != replica: 73 raise Exception('r_start does not match number of replicas') 74 r_start = [o if o else None for o in r_start] 75 else: 76 r_start = [None] * replica 77 78 if 'r_stop' in kwargs: 79 r_stop = kwargs.get('r_stop') 80 if len(r_stop) != replica: 81 raise Exception('r_stop does not match number of replicas') 82 else: 83 r_stop = [None] * replica 84 85 if 'r_step' in kwargs: 86 r_step = kwargs.get('r_step') 87 else: 88 r_step = 1 89 90 print('Read reweighting factors from', prefix[:-1], ',', 91 replica, 'replica', end='') 92 93 if names is None: 94 rep_names = [] 95 for entry in ls: 96 truncated_entry = entry 97 suffixes = [".dat", ".rwms", ".ms1"] 98 for suffix in suffixes: 99 if truncated_entry.endswith(suffix): 100 truncated_entry = truncated_entry[0:-len(suffix)] 101 idx = truncated_entry.index('r') 102 rep_names.append(truncated_entry[:idx] + '|' + truncated_entry[idx:]) 103 else: 104 rep_names = names 105 106 print_err = 0 107 if 'print_err' in kwargs: 108 print_err = 1 109 print() 110 111 deltas = [] 112 113 configlist = [] 114 r_start_index = [] 115 r_stop_index = [] 116 117 for rep in range(replica): 118 tmp_array = [] 119 with open(path + '/' + ls[rep], 'rb') as fp: 120 121 t = fp.read(4) # number of reweighting factors 122 if rep == 0: 123 nrw = struct.unpack('i', t)[0] 124 if version == '2.0': 125 nrw = int(nrw / 2) 126 for k in range(nrw): 127 deltas.append([]) 128 else: 129 if ((nrw != struct.unpack('i', t)[0] and (not version == '2.0')) or (nrw != struct.unpack('i', t)[0] / 2 and version == '2.0')): 130 raise Exception('Error: different number of reweighting factors for replicum', rep) 131 132 for k in range(nrw): 133 tmp_array.append([]) 134 135 # This block is necessary for openQCD1.6 and openQCD2.0 ms1 files 136 nfct = [] 137 if version in ['1.6', '2.0']: 138 for i in range(nrw): 139 t = fp.read(4) 140 nfct.append(struct.unpack('i', t)[0]) 141 else: 142 for i in range(nrw): 143 nfct.append(1) 144 145 nsrc = [] 146 for i in range(nrw): 147 t = fp.read(4) 148 nsrc.append(struct.unpack('i', t)[0]) 149 if version == '2.0': 150 if not struct.unpack('i', fp.read(4))[0] == 0: 151 print('something is wrong!') 152 153 configlist.append([]) 154 while 0 < 1: 155 t = fp.read(4) 156 if len(t) < 4: 157 break 158 config_no = struct.unpack('i', t)[0] 159 configlist[-1].append(config_no) 160 for i in range(nrw): 161 if(version == '2.0'): 162 tmpd = _read_array_openQCD2(fp) 163 tmpd = _read_array_openQCD2(fp) 164 tmp_rw = tmpd['arr'] 165 tmp_nfct = 1.0 166 for j in range(tmpd['n'][0]): 167 tmp_nfct *= np.mean(np.exp(-np.asarray(tmp_rw[j]))) 168 if print_err: 169 print(config_no, i, j, 170 np.mean(np.exp(-np.asarray(tmp_rw[j]))), 171 np.std(np.exp(-np.asarray(tmp_rw[j])))) 172 print('Sources:', 173 np.exp(-np.asarray(tmp_rw[j]))) 174 print('Partial factor:', tmp_nfct) 175 elif version == '1.6' or version == '1.4': 176 tmp_nfct = 1.0 177 for j in range(nfct[i]): 178 t = fp.read(8 * nsrc[i]) 179 t = fp.read(8 * nsrc[i]) 180 tmp_rw = struct.unpack('d' * nsrc[i], t) 181 tmp_nfct *= np.mean(np.exp(-np.asarray(tmp_rw))) 182 if print_err: 183 print(config_no, i, j, 184 np.mean(np.exp(-np.asarray(tmp_rw))), 185 np.std(np.exp(-np.asarray(tmp_rw)))) 186 print('Sources:', np.exp(-np.asarray(tmp_rw))) 187 print('Partial factor:', tmp_nfct) 188 tmp_array[i].append(tmp_nfct) 189 190 diffmeas = configlist[-1][-1] - configlist[-1][-2] 191 configlist[-1] = [item // diffmeas for item in configlist[-1]] 192 if configlist[-1][0] > 1 and diffmeas > 1: 193 warnings.warn('Assume thermalization and that the first measurement belongs to the first config.') 194 offset = configlist[-1][0] - 1 195 configlist[-1] = [item - offset for item in configlist[-1]] 196 197 if r_start[rep] is None: 198 r_start_index.append(0) 199 else: 200 try: 201 r_start_index.append(configlist[-1].index(r_start[rep])) 202 except ValueError: 203 raise Exception('Config %d not in file with range [%d, %d]' % ( 204 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None 205 206 if r_stop[rep] is None: 207 r_stop_index.append(len(configlist[-1]) - 1) 208 else: 209 try: 210 r_stop_index.append(configlist[-1].index(r_stop[rep])) 211 except ValueError: 212 raise Exception('Config %d not in file with range [%d, %d]' % ( 213 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None 214 215 for k in range(nrw): 216 deltas[k].append(tmp_array[k][r_start_index[rep]:r_stop_index[rep] + 1][::r_step]) 217 218 if np.any([len(np.unique(np.diff(cl))) != 1 for cl in configlist]): 219 raise Exception('Irregular spaced data in input file!', [len(np.unique(np.diff(cl))) for cl in configlist]) 220 stepsizes = [list(np.unique(np.diff(cl)))[0] for cl in configlist] 221 if np.any([step != 1 for step in stepsizes]): 222 warnings.warn('Stepsize between configurations is greater than one!' + str(stepsizes), RuntimeWarning) 223 224 print(',', nrw, 'reweighting factors with', nsrc, 'sources') 225 result = [] 226 idl = [range(configlist[rep][r_start_index[rep]], configlist[rep][r_stop_index[rep]] + 1, r_step) for rep in range(replica)] 227 228 for t in range(nrw): 229 result.append(Obs(deltas[t], rep_names, idl=idl)) 230 return result
Read rwms format from given folder structure. Returns a list of length nrw
Parameters
- path (str): path that contains the data files
- prefix (str): all files in path that start with prefix are considered as input files. May be used together postfix to consider only special file endings. Prefix is ignored, if the keyword 'files' is used.
- version (str): version of openQCD, default 2.0
- names (list): list of names that is assigned to the data according according to the order in the file list. Use careful, if you do not provide file names!
- r_start (list): list which contains the first config to be read for each replicum
- r_stop (list): list which contains the last config to be read for each replicum
- r_step (int): integer that defines a fixed step size between two measurements (in units of configs) If not given, r_step=1 is assumed.
- postfix (str): postfix of the file to read, e.g. '.ms1' for openQCD-files
- files (list): list which contains the filenames to be read. No automatic detection of files performed if given.
- print_err (bool): Print additional information that is useful for debugging.
233def extract_t0(path, prefix, dtr_read, xmin, spatial_extent, fit_range=5, **kwargs): 234 """Extract t0 from given .ms.dat files. Returns t0 as Obs. 235 236 It is assumed that all boundary effects have 237 sufficiently decayed at x0=xmin. 238 The data around the zero crossing of t^2<E> - 0.3 239 is fitted with a linear function 240 from which the exact root is extracted. 241 242 It is assumed that one measurement is performed for each config. 243 If this is not the case, the resulting idl, as well as the handling 244 of r_start, r_stop and r_step is wrong and the user has to correct 245 this in the resulting observable. 246 247 Parameters 248 ---------- 249 path : str 250 Path to .ms.dat files 251 prefix : str 252 Ensemble prefix 253 dtr_read : int 254 Determines how many trajectories should be skipped 255 when reading the ms.dat files. 256 Corresponds to dtr_cnfg / dtr_ms in the openQCD input file. 257 xmin : int 258 First timeslice where the boundary 259 effects have sufficiently decayed. 260 spatial_extent : int 261 spatial extent of the lattice, required for normalization. 262 fit_range : int 263 Number of data points left and right of the zero 264 crossing to be included in the linear fit. (Default: 5) 265 r_start : list 266 list which contains the first config to be read for each replicum. 267 r_stop : list 268 list which contains the last config to be read for each replicum. 269 r_step : int 270 integer that defines a fixed step size between two measurements (in units of configs) 271 If not given, r_step=1 is assumed. 272 plaquette : bool 273 If true extract the plaquette estimate of t0 instead. 274 names : list 275 list of names that is assigned to the data according according 276 to the order in the file list. Use careful, if you do not provide file names! 277 files : list 278 list which contains the filenames to be read. No automatic detection of 279 files performed if given. 280 plot_fit : bool 281 If true, the fit for the extraction of t0 is shown together with the data. 282 assume_thermalization : bool 283 If True: If the first record divided by the distance between two measurements is larger than 284 1, it is assumed that this is due to thermalization and the first measurement belongs 285 to the first config (default). 286 If False: The config numbers are assumed to be traj_number // difference 287 """ 288 289 ls = [] 290 for (dirpath, dirnames, filenames) in os.walk(path): 291 ls.extend(filenames) 292 break 293 294 if not ls: 295 raise Exception('Error, directory not found') 296 297 if 'files' in kwargs: 298 ls = kwargs.get('files') 299 else: 300 for exc in ls: 301 if not fnmatch.fnmatch(exc, prefix + '*.ms.dat'): 302 ls = list(set(ls) - set([exc])) 303 if len(ls) > 1: 304 ls.sort(key=lambda x: int(re.findall(r'\d+', x[len(prefix):])[0])) 305 replica = len(ls) 306 307 if 'r_start' in kwargs: 308 r_start = kwargs.get('r_start') 309 if len(r_start) != replica: 310 raise Exception('r_start does not match number of replicas') 311 r_start = [o if o else None for o in r_start] 312 else: 313 r_start = [None] * replica 314 315 if 'r_stop' in kwargs: 316 r_stop = kwargs.get('r_stop') 317 if len(r_stop) != replica: 318 raise Exception('r_stop does not match number of replicas') 319 else: 320 r_stop = [None] * replica 321 322 if 'r_step' in kwargs: 323 r_step = kwargs.get('r_step') 324 else: 325 r_step = 1 326 327 print('Extract t0 from', prefix, ',', replica, 'replica') 328 329 if 'names' in kwargs: 330 rep_names = kwargs.get('names') 331 else: 332 rep_names = [] 333 for entry in ls: 334 truncated_entry = entry.split('.')[0] 335 idx = truncated_entry.index('r') 336 rep_names.append(truncated_entry[:idx] + '|' + truncated_entry[idx:]) 337 338 Ysum = [] 339 340 configlist = [] 341 r_start_index = [] 342 r_stop_index = [] 343 344 for rep in range(replica): 345 346 with open(path + '/' + ls[rep], 'rb') as fp: 347 t = fp.read(12) 348 header = struct.unpack('iii', t) 349 if rep == 0: 350 dn = header[0] 351 nn = header[1] 352 tmax = header[2] 353 elif dn != header[0] or nn != header[1] or tmax != header[2]: 354 raise Exception('Replica parameters do not match.') 355 356 t = fp.read(8) 357 if rep == 0: 358 eps = struct.unpack('d', t)[0] 359 print('Step size:', eps, ', Maximal t value:', dn * (nn) * eps) 360 elif eps != struct.unpack('d', t)[0]: 361 raise Exception('Values for eps do not match among replica.') 362 363 Ysl = [] 364 365 configlist.append([]) 366 while 0 < 1: 367 t = fp.read(4) 368 if(len(t) < 4): 369 break 370 nc = struct.unpack('i', t)[0] 371 configlist[-1].append(nc) 372 373 t = fp.read(8 * tmax * (nn + 1)) 374 if kwargs.get('plaquette'): 375 if nc % dtr_read == 0: 376 Ysl.append(struct.unpack('d' * tmax * (nn + 1), t)) 377 t = fp.read(8 * tmax * (nn + 1)) 378 if not kwargs.get('plaquette'): 379 if nc % dtr_read == 0: 380 Ysl.append(struct.unpack('d' * tmax * (nn + 1), t)) 381 t = fp.read(8 * tmax * (nn + 1)) 382 383 Ysum.append([]) 384 for i, item in enumerate(Ysl): 385 Ysum[-1].append([np.mean(item[current + xmin: 386 current + tmax - xmin]) 387 for current in range(0, len(item), tmax)]) 388 389 diffmeas = configlist[-1][-1] - configlist[-1][-2] 390 configlist[-1] = [item // diffmeas for item in configlist[-1]] 391 if kwargs.get('assume_thermalization', True) and configlist[-1][0] > 1: 392 warnings.warn('Assume thermalization and that the first measurement belongs to the first config.') 393 offset = configlist[-1][0] - 1 394 configlist[-1] = [item - offset for item in configlist[-1]] 395 396 if r_start[rep] is None: 397 r_start_index.append(0) 398 else: 399 try: 400 r_start_index.append(configlist[-1].index(r_start[rep])) 401 except ValueError: 402 raise Exception('Config %d not in file with range [%d, %d]' % ( 403 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None 404 405 if r_stop[rep] is None: 406 r_stop_index.append(len(configlist[-1]) - 1) 407 else: 408 try: 409 r_stop_index.append(configlist[-1].index(r_stop[rep])) 410 except ValueError: 411 raise Exception('Config %d not in file with range [%d, %d]' % ( 412 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None 413 414 if np.any([len(np.unique(np.diff(cl))) != 1 for cl in configlist]): 415 raise Exception('Irregular spaced data in input file!', [len(np.unique(np.diff(cl))) for cl in configlist]) 416 stepsizes = [list(np.unique(np.diff(cl)))[0] for cl in configlist] 417 if np.any([step != 1 for step in stepsizes]): 418 warnings.warn('Stepsize between configurations is greater than one!' + str(stepsizes), RuntimeWarning) 419 420 idl = [range(configlist[rep][r_start_index[rep]], configlist[rep][r_stop_index[rep]] + 1, r_step) for rep in range(replica)] 421 t2E_dict = {} 422 for n in range(nn + 1): 423 samples = [] 424 for nrep, rep in enumerate(Ysum): 425 samples.append([]) 426 for cnfg in rep: 427 samples[-1].append(cnfg[n]) 428 samples[-1] = samples[-1][r_start_index[nrep]:r_stop_index[nrep] + 1][::r_step] 429 new_obs = Obs(samples, rep_names, idl=idl) 430 t2E_dict[n * dn * eps] = (n * dn * eps) ** 2 * new_obs / (spatial_extent ** 3) - 0.3 431 432 zero_crossing = np.argmax(np.array( 433 [o.value for o in t2E_dict.values()]) > 0.0) 434 435 x = list(t2E_dict.keys())[zero_crossing - fit_range: 436 zero_crossing + fit_range] 437 y = list(t2E_dict.values())[zero_crossing - fit_range: 438 zero_crossing + fit_range] 439 [o.gamma_method() for o in y] 440 441 fit_result = fit_lin(x, y) 442 443 if kwargs.get('plot_fit'): 444 plt.figure() 445 gs = gridspec.GridSpec(2, 1, height_ratios=[3, 1], wspace=0.0, hspace=0.0) 446 ax0 = plt.subplot(gs[0]) 447 xmore = list(t2E_dict.keys())[zero_crossing - fit_range - 2: zero_crossing + fit_range + 2] 448 ymore = list(t2E_dict.values())[zero_crossing - fit_range - 2: zero_crossing + fit_range + 2] 449 [o.gamma_method() for o in ymore] 450 ax0.errorbar(xmore, [yi.value for yi in ymore], yerr=[yi.dvalue for yi in ymore], fmt='x') 451 xplot = np.linspace(np.min(x), np.max(x)) 452 yplot = [fit_result[0] + fit_result[1] * xi for xi in xplot] 453 [yi.gamma_method() for yi in yplot] 454 ax0.fill_between(xplot, y1=[yi.value - yi.dvalue for yi in yplot], y2=[yi.value + yi.dvalue for yi in yplot]) 455 retval = (-fit_result[0] / fit_result[1]) 456 retval.gamma_method() 457 ylim = ax0.get_ylim() 458 ax0.fill_betweenx(ylim, x1=retval.value - retval.dvalue, x2=retval.value + retval.dvalue, color='gray', alpha=0.4) 459 ax0.set_ylim(ylim) 460 ax0.set_ylabel(r'$t^2 \langle E(t) \rangle - 0.3 $') 461 xlim = ax0.get_xlim() 462 463 fit_res = [fit_result[0] + fit_result[1] * xi for xi in x] 464 residuals = (np.asarray([o.value for o in y]) - [o.value for o in fit_res]) / np.asarray([o.dvalue for o in y]) 465 ax1 = plt.subplot(gs[1]) 466 ax1.plot(x, residuals, 'ko', ls='none', markersize=5) 467 ax1.tick_params(direction='out') 468 ax1.tick_params(axis="x", bottom=True, top=True, labelbottom=True) 469 ax1.axhline(y=0.0, ls='--', color='k') 470 ax1.fill_between(xlim, -1.0, 1.0, alpha=0.1, facecolor='k') 471 ax1.set_xlim(xlim) 472 ax1.set_ylabel('Residuals') 473 ax1.set_xlabel(r'$t/a^2$') 474 475 plt.draw() 476 return -fit_result[0] / fit_result[1]
Extract t0 from given .ms.dat files. Returns t0 as Obs.
It is assumed that all boundary effects have
sufficiently decayed at x0=xmin.
The data around the zero crossing of t^2
It is assumed that one measurement is performed for each config. If this is not the case, the resulting idl, as well as the handling of r_start, r_stop and r_step is wrong and the user has to correct this in the resulting observable.
Parameters
- path (str): Path to .ms.dat files
- prefix (str): Ensemble prefix
- dtr_read (int): Determines how many trajectories should be skipped when reading the ms.dat files. Corresponds to dtr_cnfg / dtr_ms in the openQCD input file.
- xmin (int): First timeslice where the boundary effects have sufficiently decayed.
- spatial_extent (int): spatial extent of the lattice, required for normalization.
- fit_range (int): Number of data points left and right of the zero crossing to be included in the linear fit. (Default: 5)
- r_start (list): list which contains the first config to be read for each replicum.
- r_stop (list): list which contains the last config to be read for each replicum.
- r_step (int): integer that defines a fixed step size between two measurements (in units of configs) If not given, r_step=1 is assumed.
- plaquette (bool): If true extract the plaquette estimate of t0 instead.
- names (list): list of names that is assigned to the data according according to the order in the file list. Use careful, if you do not provide file names!
- files (list): list which contains the filenames to be read. No automatic detection of files performed if given.
- plot_fit (bool): If true, the fit for the extraction of t0 is shown together with the data.
- assume_thermalization (bool): If True: If the first record divided by the distance between two measurements is larger than 1, it is assumed that this is due to thermalization and the first measurement belongs to the first config (default). If False: The config numbers are assumed to be traj_number // difference
524def read_qtop(path, prefix, c, dtr_cnfg=1, version="openQCD", **kwargs): 525 """Read the topologial charge based on openQCD gradient flow measurements. 526 527 Parameters 528 ---------- 529 path : str 530 path of the measurement files 531 prefix : str 532 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat. 533 Ignored if file names are passed explicitly via keyword files. 534 c : double 535 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L. 536 dtr_cnfg : int 537 (optional) parameter that specifies the number of measurements 538 between two configs. 539 If it is not set, the distance between two measurements 540 in the file is assumed to be the distance between two configurations. 541 steps : int 542 (optional) Distance between two configurations in units of trajectories / 543 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given 544 version : str 545 Either openQCD or sfqcd, depending on the data. 546 L : int 547 spatial length of the lattice in L/a. 548 HAS to be set if version != sfqcd, since openQCD does not provide 549 this in the header 550 r_start : list 551 list which contains the first config to be read for each replicum. 552 r_stop : list 553 list which contains the last config to be read for each replicum. 554 files : list 555 specify the exact files that need to be read 556 from path, practical if e.g. only one replicum is needed 557 names : list 558 Alternative labeling for replicas/ensembles. 559 Has to have the appropriate length. 560 Zeuthen_flow : bool 561 (optional) If True, the Zeuthen flow is used for Qtop. Only possible 562 for version=='sfqcd' If False, the Wilson flow is used. 563 integer_charge : bool 564 If True, the charge is rounded towards the nearest integer on each config. 565 """ 566 known_versions = ["openQCD", "sfqcd"] 567 568 if version not in known_versions: 569 raise Exception("Unknown openQCD version.") 570 if "steps" in kwargs: 571 steps = kwargs.get("steps") 572 if version == "sfqcd": 573 if "L" in kwargs: 574 supposed_L = kwargs.get("L") 575 else: 576 supposed_L = None 577 postfix = ".gfms.dat" 578 else: 579 if "L" not in kwargs: 580 raise Exception("This version of openQCD needs you to provide the spatial length of the lattice as parameter 'L'.") 581 else: 582 L = kwargs.get("L") 583 postfix = ".ms.dat" 584 585 if "files" in kwargs: 586 files = kwargs.get("files") 587 postfix = '' 588 else: 589 found = [] 590 files = [] 591 for (dirpath, dirnames, filenames) in os.walk(path + "/"): 592 found.extend(filenames) 593 break 594 for f in found: 595 if fnmatch.fnmatch(f, prefix + "*" + postfix): 596 files.append(f) 597 598 if 'r_start' in kwargs: 599 r_start = kwargs.get('r_start') 600 if len(r_start) != len(files): 601 raise Exception('r_start does not match number of replicas') 602 r_start = [o if o else None for o in r_start] 603 else: 604 r_start = [None] * len(files) 605 606 if 'r_stop' in kwargs: 607 r_stop = kwargs.get('r_stop') 608 if len(r_stop) != len(files): 609 raise Exception('r_stop does not match number of replicas') 610 else: 611 r_stop = [None] * len(files) 612 rep_names = [] 613 614 zeuthen = kwargs.get('Zeuthen_flow', False) 615 if zeuthen and version not in ['sfqcd']: 616 raise Exception('Zeuthen flow can only be used for version==sfqcd') 617 618 r_start_index = [] 619 r_stop_index = [] 620 deltas = [] 621 configlist = [] 622 for rep, file in enumerate(files): 623 with open(path + "/" + file, "rb") as fp: 624 625 Q = [] 626 traj_list = [] 627 if version in ['sfqcd']: 628 if zeuthen: 629 obspos = 0 630 else: 631 obspos = 8 632 t = fp.read(12) 633 header = struct.unpack('<iii', t) 634 zthfl = header[0] # Zeuthen flow -> if it's equal to 2 it means that the Zeuthen flow is also 'measured' (apart from the Wilson flow) 635 ncs = header[1] # number of different values for c in t_flow=1/8 c² L² -> measurements done for ncs c's 636 tmax = header[2] # lattice T/a 637 638 t = fp.read(12) 639 Ls = struct.unpack('<iii', t) 640 if(Ls[0] == Ls[1] and Ls[1] == Ls[2]): 641 L = Ls[0] 642 if not (supposed_L == L) and supposed_L: 643 raise Exception("It seems the length given in the header and by you contradict each other") 644 else: 645 raise Exception("Found more than one spatial length in header!") 646 647 t = fp.read(16) 648 header2 = struct.unpack('<dd', t) 649 tol = header2[0] 650 cmax = header2[1] # highest value of c used 651 652 if c > cmax: 653 raise Exception('Flow has been determined between c=0 and c=%lf with tolerance %lf' % (cmax, tol)) 654 655 if(zthfl == 2): 656 nfl = 2 # number of flows 657 else: 658 nfl = 1 659 iobs = 8 * nfl # number of flow observables calculated 660 661 while 0 < 1: 662 t = fp.read(4) 663 if(len(t) < 4): 664 break 665 traj_list.append(struct.unpack('i', t)[0]) # trajectory number when measurement was done 666 667 for j in range(ncs + 1): 668 for i in range(iobs): 669 t = fp.read(8 * tmax) 670 if (i == obspos): # determines the flow observable -> i=0 <-> Zeuthen flow 671 Q.append(struct.unpack('d' * tmax, t)) 672 673 else: 674 t = fp.read(12) 675 header = struct.unpack('<iii', t) 676 # step size in integration steps "dnms" 677 dn = header[0] 678 # number of measurements, so "ntot"/dn 679 nn = header[1] 680 # lattice T/a 681 tmax = header[2] 682 683 t = fp.read(8) 684 eps = struct.unpack('d', t)[0] 685 686 while 0 < 1: 687 t = fp.read(4) 688 if(len(t) < 4): 689 break 690 traj_list.append(struct.unpack('i', t)[0]) 691 # Wsl 692 t = fp.read(8 * tmax * (nn + 1)) 693 # Ysl 694 t = fp.read(8 * tmax * (nn + 1)) 695 # Qsl, which is asked for in this method 696 t = fp.read(8 * tmax * (nn + 1)) 697 # unpack the array of Qtops, 698 # on each timeslice t=0,...,tmax-1 and the 699 # measurement number in = 0...nn (see README.qcd1) 700 tmpd = struct.unpack('d' * tmax * (nn + 1), t) 701 Q.append(tmpd) 702 703 if len(np.unique(np.diff(traj_list))) != 1: 704 raise Exception("Irregularities in stepsize found") 705 else: 706 if 'steps' in kwargs: 707 if steps != traj_list[1] - traj_list[0]: 708 raise Exception("steps and the found stepsize are not the same") 709 else: 710 steps = traj_list[1] - traj_list[0] 711 712 configlist.append([tr // steps // dtr_cnfg for tr in traj_list]) 713 if configlist[-1][0] > 1: 714 offset = configlist[-1][0] - 1 715 warnings.warn('Assume thermalization and that the first measurement belongs to the first config. Offset = %d configs (%d trajectories / cycles)' % ( 716 offset, offset * steps)) 717 configlist[-1] = [item - offset for item in configlist[-1]] 718 719 if r_start[rep] is None: 720 r_start_index.append(0) 721 else: 722 try: 723 r_start_index.append(configlist[-1].index(r_start[rep])) 724 except ValueError: 725 raise Exception('Config %d not in file with range [%d, %d]' % ( 726 r_start[rep], configlist[-1][0], configlist[-1][-1])) from None 727 728 if r_stop[rep] is None: 729 r_stop_index.append(len(configlist[-1]) - 1) 730 else: 731 try: 732 r_stop_index.append(configlist[-1].index(r_stop[rep])) 733 except ValueError: 734 raise Exception('Config %d not in file with range [%d, %d]' % ( 735 r_stop[rep], configlist[-1][0], configlist[-1][-1])) from None 736 737 if version in ['sfqcd']: 738 cstepsize = cmax / ncs 739 index_aim = round(c / cstepsize) 740 else: 741 t_aim = (c * L) ** 2 / 8 742 index_aim = round(t_aim / eps / dn) 743 744 Q_sum = [] 745 for i, item in enumerate(Q): 746 Q_sum.append([sum(item[current:current + tmax]) 747 for current in range(0, len(item), tmax)]) 748 Q_top = [] 749 if version in ['sfqcd']: 750 for i in range(len(Q_sum) // (ncs + 1)): 751 Q_top.append(Q_sum[i * (ncs + 1) + index_aim][0]) 752 else: 753 for i in range(len(Q) // dtr_cnfg): 754 Q_top.append(Q_sum[dtr_cnfg * i][index_aim]) 755 if len(Q_top) != len(traj_list) // dtr_cnfg: 756 raise Exception("qtops and traj_list dont have the same length") 757 758 if kwargs.get('integer_charge', False): 759 Q_top = [round(q) for q in Q_top] 760 761 truncated_file = file[:-len(postfix)] 762 763 if "names" not in kwargs: 764 try: 765 idx = truncated_file.index('r') 766 except Exception: 767 if "names" not in kwargs: 768 raise Exception("Automatic recognition of replicum failed, please enter the key word 'names'.") 769 ens_name = truncated_file[:idx] 770 rep_names.append(ens_name + '|' + truncated_file[idx:]) 771 else: 772 names = kwargs.get("names") 773 rep_names = names 774 deltas.append(Q_top) 775 776 idl = [range(int(configlist[rep][r_start_index[rep]]), int(configlist[rep][r_stop_index[rep]]) + 1, 1) for rep in range(len(deltas))] 777 deltas = [deltas[nrep][r_start_index[nrep]:r_stop_index[nrep] + 1] for nrep in range(len(deltas))] 778 result = Obs(deltas, rep_names, idl=idl) 779 return result
Read the topologial charge based on openQCD gradient flow measurements.
Parameters
- path (str): path of the measurement files
- prefix (str):
prefix of the measurement files, e.g.
_id0_r0.ms.dat. Ignored if file names are passed explicitly via keyword files. - c (double): Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L.
- dtr_cnfg (int): (optional) parameter that specifies the number of measurements between two configs. If it is not set, the distance between two measurements in the file is assumed to be the distance between two configurations.
- steps (int): (optional) Distance between two configurations in units of trajectories / cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given
- version (str): Either openQCD or sfqcd, depending on the data.
- L (int): spatial length of the lattice in L/a. HAS to be set if version != sfqcd, since openQCD does not provide this in the header
- r_start (list): list which contains the first config to be read for each replicum.
- r_stop (list): list which contains the last config to be read for each replicum.
- files (list): specify the exact files that need to be read from path, practical if e.g. only one replicum is needed
- names (list): Alternative labeling for replicas/ensembles. Has to have the appropriate length.
- Zeuthen_flow (bool): (optional) If True, the Zeuthen flow is used for Qtop. Only possible for version=='sfqcd' If False, the Wilson flow is used.
- integer_charge (bool): If True, the charge is rounded towards the nearest integer on each config.
782def qtop_projection(qtop, target=0): 783 """Returns the projection to the topological charge sector defined by target. 784 785 Parameters 786 ---------- 787 path : Obs 788 Topological charge. 789 target : int 790 Specifies the topological sector to be reweighted to (default 0) 791 """ 792 if qtop.reweighted: 793 raise Exception('You can not use a reweighted observable for reweighting!') 794 795 proj_qtop = [] 796 for n in qtop.deltas: 797 proj_qtop.append(np.array([1 if round(qtop.value + q) == target else 0 for q in qtop.deltas[n]])) 798 799 reto = Obs(proj_qtop, qtop.names, idl=[qtop.idl[name] for name in qtop.names]) 800 reto.is_merged = qtop.is_merged 801 return reto
Returns the projection to the topological charge sector defined by target.
Parameters
- path (Obs): Topological charge.
- target (int): Specifies the topological sector to be reweighted to (default 0)
804def read_qtop_sector(path, prefix, c, target=0, **kwargs): 805 """Constructs reweighting factors to a specified topological sector. 806 807 Parameters 808 ---------- 809 path : str 810 path of the measurement files 811 prefix : str 812 prefix of the measurement files, e.g. <prefix>_id0_r0.ms.dat 813 c : double 814 Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L 815 target : int 816 Specifies the topological sector to be reweighted to (default 0) 817 dtr_cnfg : int 818 (optional) parameter that specifies the number of trajectories 819 between two configs. 820 if it is not set, the distance between two measurements 821 in the file is assumed to be the distance between two configurations. 822 steps : int 823 (optional) Distance between two configurations in units of trajectories / 824 cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given 825 version : str 826 version string of the openQCD (sfqcd) version used to create 827 the ensemble. Default is 2.0. May also be set to sfqcd. 828 L : int 829 spatial length of the lattice in L/a. 830 HAS to be set if version != sfqcd, since openQCD does not provide 831 this in the header 832 r_start : list 833 offset of the first ensemble, making it easier to match 834 later on with other Obs 835 r_stop : list 836 last configurations that need to be read (per replicum) 837 files : list 838 specify the exact files that need to be read 839 from path, practical if e.g. only one replicum is needed 840 names : list 841 Alternative labeling for replicas/ensembles. 842 Has to have the appropriate length 843 Zeuthen_flow : bool 844 (optional) If True, the Zeuthen flow is used for Qtop. Only possible 845 for version=='sfqcd' If False, the Wilson flow is used. 846 """ 847 848 if not isinstance(target, int): 849 raise Exception("'target' has to be an integer.") 850 851 kwargs['integer_charge'] = True 852 qtop = read_qtop(path, prefix, c, **kwargs) 853 854 return qtop_projection(qtop, target=target)
Constructs reweighting factors to a specified topological sector.
Parameters
- path (str): path of the measurement files
- prefix (str):
prefix of the measurement files, e.g.
_id0_r0.ms.dat - c (double): Smearing radius in units of the lattice extent, c = sqrt(8 t0) / L
- target (int): Specifies the topological sector to be reweighted to (default 0)
- dtr_cnfg (int): (optional) parameter that specifies the number of trajectories between two configs. if it is not set, the distance between two measurements in the file is assumed to be the distance between two configurations.
- steps (int): (optional) Distance between two configurations in units of trajectories / cycles. Assumed to be the distance between two measurements * dtr_cnfg if not given
- version (str): version string of the openQCD (sfqcd) version used to create the ensemble. Default is 2.0. May also be set to sfqcd.
- L (int): spatial length of the lattice in L/a. HAS to be set if version != sfqcd, since openQCD does not provide this in the header
- r_start (list): offset of the first ensemble, making it easier to match later on with other Obs
- r_stop (list): last configurations that need to be read (per replicum)
- files (list): specify the exact files that need to be read from path, practical if e.g. only one replicum is needed
- names (list): Alternative labeling for replicas/ensembles. Has to have the appropriate length
- Zeuthen_flow (bool): (optional) If True, the Zeuthen flow is used for Qtop. Only possible for version=='sfqcd' If False, the Wilson flow is used.