pyerrors.input.sfcf
1import os 2import fnmatch 3import re 4import numpy as np # Thinly-wrapped numpy 5from ..obs import Obs 6from .utils import sort_names, check_idl 7import itertools 8import warnings 9 10 11sep = "/" 12 13 14def read_sfcf(path, prefix, name, quarks='.*', corr_type="bi", noffset=0, wf=0, wf2=0, version="1.0c", cfg_separator="n", cfg_func=None, silent=False, **kwargs): 15 """Read sfcf files from given folder structure. 16 17 Parameters 18 ---------- 19 path : str 20 Path to the sfcf files. 21 prefix : str 22 Prefix of the sfcf files. 23 name : str 24 Name of the correlation function to read. 25 quarks : str 26 Label of the quarks used in the sfcf input file. e.g. "quark quark" 27 for version 0.0 this does NOT need to be given with the typical " - " 28 that is present in the output file, 29 this is done automatically for this version 30 corr_type : str 31 Type of correlation function to read. Can be 32 - 'bi' for boundary-inner 33 - 'bb' for boundary-boundary 34 - 'bib' for boundary-inner-boundary 35 noffset : int 36 Offset of the source (only relevant when wavefunctions are used) 37 wf : int 38 ID of wave function 39 wf2 : int 40 ID of the second wavefunction 41 (only relevant for boundary-to-boundary correlation functions) 42 im : bool 43 if True, read imaginary instead of real part 44 of the correlation function. 45 names : list 46 Alternative labeling for replicas/ensembles. 47 Has to have the appropriate length 48 ens_name : str 49 replaces the name of the ensemble 50 version: str 51 version of SFCF, with which the measurement was done. 52 if the compact output option (-c) was specified, 53 append a "c" to the version (e.g. "1.0c") 54 if the append output option (-a) was specified, 55 append an "a" to the version 56 cfg_separator : str 57 String that separates the ensemble identifier from the configuration number (default 'n'). 58 replica: list 59 list of replica to be read, default is all 60 files: list 61 list of files to be read per replica, default is all. 62 for non-compact output format, hand the folders to be read here. 63 check_configs: list[list[int]] 64 list of list of supposed configs, eg. [range(1,1000)] 65 for one replicum with 1000 configs 66 67 Returns 68 ------- 69 result: list[Obs] 70 list of Observables with length T, observable per timeslice. 71 bb-type correlators have length 1. 72 """ 73 ret = read_sfcf_multi(path, prefix, [name], quarks_list=[quarks], corr_type_list=[corr_type], 74 noffset_list=[noffset], wf_list=[wf], wf2_list=[wf2], version=version, 75 cfg_separator=cfg_separator, cfg_func=cfg_func, silent=silent, **kwargs) 76 return ret[name][quarks][str(noffset)][str(wf)][str(wf2)] 77 78 79def read_sfcf_multi(path, prefix, name_list, quarks_list=['.*'], corr_type_list=['bi'], noffset_list=[0], wf_list=[0], wf2_list=[0], version="1.0c", cfg_separator="n", cfg_func=None, silent=False, keyed_out=False, **kwargs): 80 """Read sfcf files from given folder structure. 81 82 Parameters 83 ---------- 84 path : str 85 Path to the sfcf files. 86 prefix : str 87 Prefix of the sfcf files. 88 name : str 89 Name of the correlation function to read. 90 quarks_list : list[str] 91 Label of the quarks used in the sfcf input file. e.g. "quark quark" 92 for version 0.0 this does NOT need to be given with the typical " - " 93 that is present in the output file, 94 this is done automatically for this version 95 corr_type_list : list[str] 96 Type of correlation function to read. Can be 97 - 'bi' for boundary-inner 98 - 'bb' for boundary-boundary 99 - 'bib' for boundary-inner-boundary 100 noffset_list : list[int] 101 Offset of the source (only relevant when wavefunctions are used) 102 wf_list : int 103 ID of wave function 104 wf2_list : list[int] 105 ID of the second wavefunction 106 (only relevant for boundary-to-boundary correlation functions) 107 im : bool 108 if True, read imaginary instead of real part 109 of the correlation function. 110 names : list 111 Alternative labeling for replicas/ensembles. 112 Has to have the appropriate length 113 ens_name : str 114 replaces the name of the ensemble 115 version: str 116 version of SFCF, with which the measurement was done. 117 if the compact output option (-c) was specified, 118 append a "c" to the version (e.g. "1.0c") 119 if the append output option (-a) was specified, 120 append an "a" to the version 121 cfg_separator : str 122 String that separates the ensemble identifier from the configuration number (default 'n'). 123 replica: list 124 list of replica to be read, default is all 125 files: list[list[int]] 126 list of files to be read per replica, default is all. 127 for non-compact output format, hand the folders to be read here. 128 check_configs: list[list[int]] 129 list of list of supposed configs, eg. [range(1,1000)] 130 for one replicum with 1000 configs 131 rep_string: str 132 Separator of ensemble name and replicum. Example: In "ensAr0", "r" would be the separator string. 133 Returns 134 ------- 135 result: dict[list[Obs]] 136 dict with one of the following properties: 137 if keyed_out: 138 dict[key] = list[Obs] 139 where key has the form name/quarks/offset/wf/wf2 140 if not keyed_out: 141 dict[name][quarks][offset][wf][wf2] = list[Obs] 142 """ 143 144 if kwargs.get('im'): 145 im = 1 146 part = 'imaginary' 147 else: 148 im = 0 149 part = 'real' 150 151 known_versions = ["0.0", "1.0", "2.0", "1.0c", "2.0c", "1.0a", "2.0a"] 152 153 if version not in known_versions: 154 raise Exception("This version is not known!") 155 if (version[-1] == "c"): 156 appended = False 157 compact = True 158 version = version[:-1] 159 elif (version[-1] == "a"): 160 appended = True 161 compact = False 162 version = version[:-1] 163 else: 164 compact = False 165 appended = False 166 ls = [] 167 if "replica" in kwargs: 168 ls = kwargs.get("replica") 169 else: 170 for (dirpath, dirnames, filenames) in os.walk(path): 171 if not appended: 172 ls.extend(dirnames) 173 else: 174 ls.extend(filenames) 175 break 176 if not ls: 177 raise Exception('Error, directory not found') 178 # Exclude folders with different names 179 for exc in ls: 180 if not fnmatch.fnmatch(exc, prefix + '*'): 181 ls = list(set(ls) - set([exc])) 182 183 if not appended: 184 ls = sort_names(ls) 185 replica = len(ls) 186 187 else: 188 replica = len([file.split(".")[-1] for file in ls]) // len(set([file.split(".")[-1] for file in ls])) 189 if replica == 0: 190 raise Exception('No replica found in directory') 191 if not silent: 192 print('Read', part, 'part of', name_list, 'from', prefix[:-1], ',', replica, 'replica') 193 194 if 'names' in kwargs: 195 new_names = kwargs.get('names') 196 if len(new_names) != len(set(new_names)): 197 raise Exception("names are not unique!") 198 if len(new_names) != replica: 199 raise Exception('names should have the length', replica) 200 201 else: 202 ens_name = kwargs.get("ens_name") 203 if not appended: 204 new_names = _get_rep_names(ls, ens_name, rep_sep=(kwargs.get('rep_string', 'r'))) 205 else: 206 new_names = _get_appended_rep_names(ls, prefix, name_list[0], ens_name, rep_sep=(kwargs.get('rep_string', 'r'))) 207 new_names = sort_names(new_names) 208 209 idl = [] 210 211 noffset_list = [str(x) for x in noffset_list] 212 wf_list = [str(x) for x in wf_list] 213 wf2_list = [str(x) for x in wf2_list] 214 215 # setup dict structures 216 intern = {} 217 for name, corr_type in zip(name_list, corr_type_list): 218 intern[name] = {} 219 b2b, single = _extract_corr_type(corr_type) 220 intern[name]["b2b"] = b2b 221 intern[name]["single"] = single 222 intern[name]["spec"] = {} 223 for quarks in quarks_list: 224 intern[name]["spec"][quarks] = {} 225 for off in noffset_list: 226 intern[name]["spec"][quarks][off] = {} 227 for w in wf_list: 228 intern[name]["spec"][quarks][off][w] = {} 229 if b2b: 230 for w2 in wf2_list: 231 intern[name]["spec"][quarks][off][w][w2] = {} 232 intern[name]["spec"][quarks][off][w][w2]["pattern"] = _make_pattern(version, name, off, w, w2, intern[name]['b2b'], quarks) 233 else: 234 intern[name]["spec"][quarks][off][w]["0"] = {} 235 intern[name]["spec"][quarks][off][w]["0"]["pattern"] = _make_pattern(version, name, off, w, 0, intern[name]['b2b'], quarks) 236 237 internal_ret_dict = {} 238 needed_keys = [] 239 for name, corr_type in zip(name_list, corr_type_list): 240 b2b, single = _extract_corr_type(corr_type) 241 if b2b: 242 needed_keys.extend(_lists2key([name], quarks_list, noffset_list, wf_list, wf2_list)) 243 else: 244 needed_keys.extend(_lists2key([name], quarks_list, noffset_list, wf_list, ["0"])) 245 246 for key in needed_keys: 247 internal_ret_dict[key] = [] 248 249 def _default_idl_func(cfg_string, cfg_sep): 250 return int(cfg_string.split(cfg_sep)[-1]) 251 252 if cfg_func is None: 253 print("Default idl function in use.") 254 cfg_func = _default_idl_func 255 cfg_func_args = [cfg_separator] 256 else: 257 cfg_func_args = kwargs.get("cfg_func_args", []) 258 259 if not appended: 260 for i, item in enumerate(ls): 261 rep_path = path + '/' + item 262 if "files" in kwargs: 263 files = kwargs.get("files") 264 if isinstance(files, list): 265 if all(isinstance(f, list) for f in files): 266 files = files[i] 267 elif all(isinstance(f, str) for f in files): 268 files = files 269 else: 270 raise TypeError("files has to be of type list[list[str]] or list[str]!") 271 else: 272 raise TypeError("files has to be of type list[list[str]] or list[str]!") 273 274 else: 275 files = [] 276 sub_ls = _find_files(rep_path, prefix, compact, files) 277 rep_idl = [] 278 no_cfg = len(sub_ls) 279 for cfg in sub_ls: 280 try: 281 if compact: 282 rep_idl.append(cfg_func(cfg, *cfg_func_args)) 283 else: 284 rep_idl.append(int(cfg[3:])) 285 except Exception: 286 raise Exception("Couldn't parse idl from directory, problem with file " + cfg) 287 rep_idl.sort() 288 # maybe there is a better way to print the idls 289 if not silent: 290 print(item, ':', no_cfg, ' configurations') 291 idl.append(rep_idl) 292 # here we have found all the files we need to look into. 293 if i == 0: 294 if version != "0.0" and compact: 295 file = path + '/' + item + '/' + sub_ls[0] 296 for name_index, name in enumerate(name_list): 297 if version == "0.0" or not compact: 298 file = path + '/' + item + '/' + sub_ls[0] + '/' + name 299 if corr_type_list[name_index] == 'bi': 300 name_keys = _lists2key(quarks_list, noffset_list, wf_list, ["0"]) 301 else: 302 name_keys = _lists2key(quarks_list, noffset_list, wf_list, wf2_list) 303 for key in name_keys: 304 specs = _key2specs(key) 305 quarks = specs[0] 306 off = specs[1] 307 w = specs[2] 308 w2 = specs[3] 309 # here, we want to find the place within the file, 310 # where the correlator we need is stored. 311 # to do so, the pattern needed is put together 312 # from the input values 313 start_read, T = _find_correlator(file, version, intern[name]["spec"][quarks][str(off)][str(w)][str(w2)]["pattern"], intern[name]['b2b'], silent=silent) 314 intern[name]["spec"][quarks][str(off)][str(w)][str(w2)]["start"] = start_read 315 intern[name]["T"] = T 316 # preparing the datastructure 317 # the correlators get parsed into... 318 deltas = [] 319 for j in range(intern[name]["T"]): 320 deltas.append([]) 321 internal_ret_dict[sep.join([name, key])] = deltas 322 323 if compact: 324 rep_deltas = _read_compact_rep(path, item, sub_ls, intern, needed_keys, im) 325 for key in needed_keys: 326 name = _key2specs(key)[0] 327 for t in range(intern[name]["T"]): 328 internal_ret_dict[key][t].append(rep_deltas[key][t]) 329 else: 330 for key in needed_keys: 331 rep_data = [] 332 name = _key2specs(key)[0] 333 for subitem in sub_ls: 334 cfg_path = path + '/' + item + '/' + subitem 335 file_data = _read_o_file(cfg_path, name, needed_keys, intern, version, im) 336 rep_data.append(file_data) 337 for t in range(intern[name]["T"]): 338 internal_ret_dict[key][t].append([]) 339 for cfg in range(no_cfg): 340 internal_ret_dict[key][t][i].append(rep_data[cfg][key][t]) 341 else: 342 for key in needed_keys: 343 specs = _key2specs(key) 344 name = specs[0] 345 quarks = specs[1] 346 off = specs[2] 347 w = specs[3] 348 w2 = specs[4] 349 if "files" in kwargs: 350 if isinstance(kwargs.get("files"), list) and all(isinstance(f, str) for f in kwargs.get("files")): 351 name_ls = kwargs.get("files") 352 else: 353 raise TypeError("In append mode, files has to be of type list[str]!") 354 else: 355 name_ls = ls 356 for exc in name_ls: 357 if not fnmatch.fnmatch(exc, prefix + '*.' + name): 358 name_ls = list(set(name_ls) - set([exc])) 359 name_ls = sort_names(name_ls) 360 pattern = intern[name]['spec'][quarks][off][w][w2]['pattern'] 361 deltas = [] 362 for rep, file in enumerate(name_ls): 363 rep_idl = [] 364 filename = path + '/' + file 365 T, rep_idl, rep_data = _read_append_rep(filename, pattern, intern[name]['b2b'], im, intern[name]['single'], cfg_func, cfg_func_args) 366 if rep == 0: 367 intern[name]['T'] = T 368 for t in range(intern[name]['T']): 369 deltas.append([]) 370 for t in range(intern[name]['T']): 371 deltas[t].append(rep_data[t]) 372 internal_ret_dict[key] = deltas 373 if name == name_list[0]: 374 idl.append(rep_idl) 375 376 if kwargs.get("check_configs") is True: 377 if not silent: 378 print("Checking for missing configs...") 379 che = kwargs.get("check_configs") 380 if not (len(che) == len(idl)): 381 raise Exception("check_configs has to be the same length as replica!") 382 for r in range(len(idl)): 383 if not silent: 384 print("checking " + new_names[r]) 385 check_idl(idl[r], che[r]) 386 if not silent: 387 print("Done") 388 389 result_dict = {} 390 if keyed_out: 391 for key in needed_keys: 392 name = _key2specs(key)[0] 393 result = [] 394 for t in range(intern[name]["T"]): 395 result.append(Obs(internal_ret_dict[key][t], new_names, idl=idl)) 396 result_dict[key] = result 397 else: 398 for name, corr_type in zip(name_list, corr_type_list): 399 result_dict[name] = {} 400 for quarks in quarks_list: 401 result_dict[name][quarks] = {} 402 for off in noffset_list: 403 result_dict[name][quarks][off] = {} 404 for w in wf_list: 405 result_dict[name][quarks][off][w] = {} 406 if corr_type != 'bi': 407 for w2 in wf2_list: 408 key = _specs2key(name, quarks, off, w, w2) 409 result = [] 410 for t in range(intern[name]["T"]): 411 result.append(Obs(internal_ret_dict[key][t], new_names, idl=idl)) 412 result_dict[name][quarks][str(off)][str(w)][str(w2)] = result 413 else: 414 key = _specs2key(name, quarks, off, w, "0") 415 result = [] 416 for t in range(intern[name]["T"]): 417 result.append(Obs(internal_ret_dict[key][t], new_names, idl=idl)) 418 result_dict[name][quarks][str(off)][str(w)][str(0)] = result 419 return result_dict 420 421 422def _lists2key(*lists): 423 keys = [] 424 for tup in itertools.product(*lists): 425 keys.append(sep.join(tup)) 426 return keys 427 428 429def _key2specs(key): 430 return key.split(sep) 431 432 433def _specs2key(*specs): 434 return sep.join(specs) 435 436 437def _read_o_file(cfg_path, name, needed_keys, intern, version, im): 438 return_vals = {} 439 for key in needed_keys: 440 file = cfg_path + '/' + name 441 specs = _key2specs(key) 442 if specs[0] == name: 443 with open(file) as fp: 444 lines = fp.readlines() 445 quarks = specs[1] 446 off = specs[2] 447 w = specs[3] 448 w2 = specs[4] 449 T = intern[name]["T"] 450 start_read = intern[name]["spec"][quarks][off][w][w2]["start"] 451 deltas = [] 452 for line in lines[start_read:start_read + T]: 453 floats = list(map(float, line.split())) 454 if version == "0.0": 455 deltas.append(floats[im - intern[name]["single"]]) 456 else: 457 deltas.append(floats[1 + im - intern[name]["single"]]) 458 return_vals[key] = deltas 459 return return_vals 460 461 462def _extract_corr_type(corr_type): 463 if corr_type == 'bb': 464 b2b = True 465 single = True 466 elif corr_type == 'bib': 467 b2b = True 468 single = False 469 else: 470 b2b = False 471 single = False 472 return b2b, single 473 474 475def _find_files(rep_path, prefix, compact, files=[]): 476 sub_ls = [] 477 if not files == []: 478 files.sort(key=lambda x: int(re.findall(r'\d+', x)[-1])) 479 else: 480 for (dirpath, dirnames, filenames) in os.walk(rep_path): 481 if compact: 482 sub_ls.extend(filenames) 483 else: 484 sub_ls.extend(dirnames) 485 break 486 if compact: 487 for exc in sub_ls: 488 if not fnmatch.fnmatch(exc, prefix + '*'): 489 sub_ls = list(set(sub_ls) - set([exc])) 490 sub_ls.sort(key=lambda x: int(re.findall(r'\d+', x)[-1])) 491 else: 492 for exc in sub_ls: 493 if not fnmatch.fnmatch(exc, 'cfg*'): 494 sub_ls = list(set(sub_ls) - set([exc])) 495 sub_ls.sort(key=lambda x: int(x[3:])) 496 files = sub_ls 497 if len(files) == 0: 498 raise FileNotFoundError("Did not find files in", rep_path, "with prefix", prefix, "and the given structure.") 499 return files 500 501 502def _make_pattern(version, name, noffset, wf, wf2, b2b, quarks): 503 if version == "0.0": 504 pattern = "# " + name + " : offset " + str(noffset) + ", wf " + str(wf) 505 if b2b: 506 pattern += ", wf_2 " + str(wf2) 507 qs = quarks.split(" ") 508 pattern += " : " + qs[0] + " - " + qs[1] 509 else: 510 pattern = 'name ' + name + '\nquarks ' + quarks + '\noffset ' + str(noffset) + '\nwf ' + str(wf) 511 if b2b: 512 pattern += '\nwf_2 ' + str(wf2) 513 return pattern 514 515 516def _find_correlator(file_name, version, pattern, b2b, silent=False): 517 T = 0 518 519 with open(file_name, "r") as my_file: 520 521 content = my_file.read() 522 match = re.search(pattern, content) 523 if match: 524 if version == "0.0": 525 start_read = content.count('\n', 0, match.start()) + 1 526 T = content.count('\n', start_read) 527 else: 528 start_read = content.count('\n', 0, match.start()) + 5 + b2b 529 end_match = re.search(r'\n\s*\n', content[match.start():]) 530 T = content[match.start():].count('\n', 0, end_match.start()) - 4 - b2b 531 if not T > 0: 532 raise ValueError("Correlator with pattern\n" + pattern + "\nis empty!") 533 if not silent: 534 print(T, 'entries, starting to read in line', start_read) 535 536 else: 537 raise ValueError('Correlator with pattern\n' + pattern + '\nnot found.') 538 539 return start_read, T 540 541 542def _read_compact_file(rep_path, cfg_file, intern, needed_keys, im): 543 return_vals = {} 544 with open(rep_path + cfg_file) as fp: 545 lines = fp.readlines() 546 for key in needed_keys: 547 keys = _key2specs(key) 548 name = keys[0] 549 quarks = keys[1] 550 off = keys[2] 551 w = keys[3] 552 w2 = keys[4] 553 554 T = intern[name]["T"] 555 start_read = intern[name]["spec"][quarks][off][w][w2]["start"] 556 # check, if the correlator is in fact 557 # printed completely 558 if (start_read + T + 1 > len(lines)): 559 raise Exception("EOF before end of correlator data! Maybe " + rep_path + cfg_file + " is corrupted?") 560 corr_lines = lines[start_read - 6: start_read + T] 561 t_vals = [] 562 563 if corr_lines[1 - intern[name]["b2b"]].strip() != 'name ' + name: 564 raise Exception('Wrong format in file', cfg_file) 565 566 for k in range(6, T + 6): 567 floats = list(map(float, corr_lines[k].split())) 568 t_vals.append(floats[-2:][im]) 569 return_vals[key] = t_vals 570 return return_vals 571 572 573def _read_compact_rep(path, rep, sub_ls, intern, needed_keys, im): 574 rep_path = path + '/' + rep + '/' 575 no_cfg = len(sub_ls) 576 577 return_vals = {} 578 for key in needed_keys: 579 name = _key2specs(key)[0] 580 deltas = [] 581 for t in range(intern[name]["T"]): 582 deltas.append(np.zeros(no_cfg)) 583 return_vals[key] = deltas 584 585 for cfg in range(no_cfg): 586 cfg_file = sub_ls[cfg] 587 cfg_data = _read_compact_file(rep_path, cfg_file, intern, needed_keys, im) 588 for key in needed_keys: 589 name = _key2specs(key)[0] 590 for t in range(intern[name]["T"]): 591 return_vals[key][t][cfg] = cfg_data[key][t] 592 return return_vals 593 594 595def _read_chunk_data(chunk, start_read, T, corr_line, b2b, pattern, im, single): 596 found_pat = "" 597 data = [] 598 for li in chunk[corr_line + 1:corr_line + 6 + b2b]: 599 found_pat += li 600 if re.search(pattern, found_pat): 601 for t, line in enumerate(chunk[start_read:start_read + T]): 602 floats = list(map(float, line.split())) 603 data.append(floats[im + 1 - single]) 604 return data 605 606 607def _check_append_rep(content, start_list): 608 data_len_list = [] 609 header_len_list = [] 610 has_regular_len_heads = True 611 for chunk_num in range(len(start_list)): 612 start = start_list[chunk_num] 613 if chunk_num == len(start_list) - 1: 614 stop = len(content) 615 else: 616 stop = start_list[chunk_num + 1] 617 chunk = content[start:stop] 618 for linenumber, line in enumerate(chunk): 619 if line.startswith("[correlator]"): 620 header_len = linenumber 621 break 622 header_len_list.append(header_len) 623 data_len_list.append(len(chunk) - header_len) 624 625 if len(set(header_len_list)) > 1: 626 warnings.warn("Not all headers have the same length. Data parts do.") 627 has_regular_len_heads = False 628 629 if len(set(data_len_list)) > 1: 630 raise Exception("Irregularities in file structure found, not all run data are of the same output length") 631 return has_regular_len_heads 632 633 634def _read_chunk_structure(chunk, pattern, b2b): 635 start_read = 0 636 for linenumber, line in enumerate(chunk): 637 if line.startswith("gauge_name"): 638 gauge_line = linenumber 639 elif line.startswith("[correlator]"): 640 corr_line = linenumber 641 found_pat = "" 642 for li in chunk[corr_line + 1: corr_line + 6 + b2b]: 643 found_pat += li 644 if re.search(pattern, found_pat): 645 start_read = corr_line + 7 + b2b 646 break 647 if start_read == 0: 648 raise ValueError("Did not find pattern\n", pattern) 649 endline = corr_line + 6 + b2b 650 while not chunk[endline] == "\n": 651 endline += 1 652 T = endline - start_read 653 return gauge_line, corr_line, start_read, T 654 655 656def _read_append_rep(filename, pattern, b2b, im, single, idl_func, cfg_func_args): 657 with open(filename, 'r') as fp: 658 content = fp.readlines() 659 chunk_start_lines = [] 660 for linenumber, line in enumerate(content): 661 if "[run]" in line: 662 chunk_start_lines.append(linenumber) 663 has_regular_len_heads = _check_append_rep(content, chunk_start_lines) 664 if has_regular_len_heads: 665 chunk = content[:chunk_start_lines[1]] 666 try: 667 gauge_line, corr_line, start_read, T = _read_chunk_structure(chunk, pattern, b2b) 668 except ValueError: 669 raise ValueError("Did not find pattern\n", pattern, "\nin\n", filename, "lines", 1, "to", chunk_start_lines[1] + 1) 670 # if has_regular_len_heads is true, all other chunks should follow the same structure 671 rep_idl = [] 672 rep_data = [] 673 674 for chunk_num in range(len(chunk_start_lines)): 675 start = chunk_start_lines[chunk_num] 676 if chunk_num == len(chunk_start_lines) - 1: 677 stop = len(content) 678 else: 679 stop = chunk_start_lines[chunk_num + 1] 680 chunk = content[start:stop] 681 if not has_regular_len_heads: 682 gauge_line, corr_line, start_read, T = _read_chunk_structure(chunk, pattern, b2b) 683 try: 684 idl = idl_func(chunk[gauge_line], *cfg_func_args) 685 except Exception: 686 raise Exception("Couldn't parse idl from file", filename, ", problem with chunk of lines", start + 1, "to", stop + 1) 687 data = _read_chunk_data(chunk, start_read, T, corr_line, b2b, pattern, im, single) 688 rep_idl.append(idl) 689 rep_data.append(data) 690 691 data = [] 692 693 for t in range(T): 694 data.append([]) 695 for c in range(len(rep_data)): 696 data[t].append(rep_data[c][t]) 697 return T, rep_idl, data 698 699 700def _get_rep_names(ls, ens_name=None, rep_sep='r'): 701 new_names = [] 702 for entry in ls: 703 try: 704 idx = entry.index(rep_sep) 705 except Exception: 706 raise Exception("Automatic recognition of replicum failed, please enter the key word 'names'.") 707 708 if ens_name: 709 new_names.append(ens_name + '|' + entry[idx:]) 710 else: 711 new_names.append(entry[:idx] + '|' + entry[idx:]) 712 return new_names 713 714 715def _get_appended_rep_names(ls, prefix, name, ens_name=None, rep_sep='r'): 716 new_names = [] 717 for exc in ls: 718 if not fnmatch.fnmatch(exc, prefix + '*.' + name): 719 ls = list(set(ls) - set([exc])) 720 ls.sort(key=lambda x: int(re.findall(r'\d+', x)[-1])) 721 for entry in ls: 722 myentry = entry[:-len(name) - 1] 723 try: 724 idx = myentry.index(rep_sep) 725 except Exception: 726 raise Exception("Automatic recognition of replicum failed, please enter the key word 'names'.") 727 728 if ens_name: 729 new_names.append(ens_name + '|' + entry[idx:]) 730 else: 731 new_names.append(myentry[:idx] + '|' + myentry[idx:]) 732 return new_names
sep =
'/'
def
read_sfcf( path, prefix, name, quarks='.*', corr_type='bi', noffset=0, wf=0, wf2=0, version='1.0c', cfg_separator='n', cfg_func=None, silent=False, **kwargs):
15def read_sfcf(path, prefix, name, quarks='.*', corr_type="bi", noffset=0, wf=0, wf2=0, version="1.0c", cfg_separator="n", cfg_func=None, silent=False, **kwargs): 16 """Read sfcf files from given folder structure. 17 18 Parameters 19 ---------- 20 path : str 21 Path to the sfcf files. 22 prefix : str 23 Prefix of the sfcf files. 24 name : str 25 Name of the correlation function to read. 26 quarks : str 27 Label of the quarks used in the sfcf input file. e.g. "quark quark" 28 for version 0.0 this does NOT need to be given with the typical " - " 29 that is present in the output file, 30 this is done automatically for this version 31 corr_type : str 32 Type of correlation function to read. Can be 33 - 'bi' for boundary-inner 34 - 'bb' for boundary-boundary 35 - 'bib' for boundary-inner-boundary 36 noffset : int 37 Offset of the source (only relevant when wavefunctions are used) 38 wf : int 39 ID of wave function 40 wf2 : int 41 ID of the second wavefunction 42 (only relevant for boundary-to-boundary correlation functions) 43 im : bool 44 if True, read imaginary instead of real part 45 of the correlation function. 46 names : list 47 Alternative labeling for replicas/ensembles. 48 Has to have the appropriate length 49 ens_name : str 50 replaces the name of the ensemble 51 version: str 52 version of SFCF, with which the measurement was done. 53 if the compact output option (-c) was specified, 54 append a "c" to the version (e.g. "1.0c") 55 if the append output option (-a) was specified, 56 append an "a" to the version 57 cfg_separator : str 58 String that separates the ensemble identifier from the configuration number (default 'n'). 59 replica: list 60 list of replica to be read, default is all 61 files: list 62 list of files to be read per replica, default is all. 63 for non-compact output format, hand the folders to be read here. 64 check_configs: list[list[int]] 65 list of list of supposed configs, eg. [range(1,1000)] 66 for one replicum with 1000 configs 67 68 Returns 69 ------- 70 result: list[Obs] 71 list of Observables with length T, observable per timeslice. 72 bb-type correlators have length 1. 73 """ 74 ret = read_sfcf_multi(path, prefix, [name], quarks_list=[quarks], corr_type_list=[corr_type], 75 noffset_list=[noffset], wf_list=[wf], wf2_list=[wf2], version=version, 76 cfg_separator=cfg_separator, cfg_func=cfg_func, silent=silent, **kwargs) 77 return ret[name][quarks][str(noffset)][str(wf)][str(wf2)]
Read sfcf files from given folder structure.
Parameters
- path (str): Path to the sfcf files.
- prefix (str): Prefix of the sfcf files.
- name (str): Name of the correlation function to read.
- quarks (str): Label of the quarks used in the sfcf input file. e.g. "quark quark" for version 0.0 this does NOT need to be given with the typical " - " that is present in the output file, this is done automatically for this version
- corr_type (str):
Type of correlation function to read. Can be
- 'bi' for boundary-inner
- 'bb' for boundary-boundary
- 'bib' for boundary-inner-boundary
- noffset (int): Offset of the source (only relevant when wavefunctions are used)
- wf (int): ID of wave function
- wf2 (int): ID of the second wavefunction (only relevant for boundary-to-boundary correlation functions)
- im (bool): if True, read imaginary instead of real part of the correlation function.
- names (list): Alternative labeling for replicas/ensembles. Has to have the appropriate length
- ens_name (str): replaces the name of the ensemble
- version (str): version of SFCF, with which the measurement was done. if the compact output option (-c) was specified, append a "c" to the version (e.g. "1.0c") if the append output option (-a) was specified, append an "a" to the version
- cfg_separator (str): String that separates the ensemble identifier from the configuration number (default 'n').
- replica (list): list of replica to be read, default is all
- files (list): list of files to be read per replica, default is all. for non-compact output format, hand the folders to be read here.
- check_configs (list[list[int]]): list of list of supposed configs, eg. [range(1,1000)] for one replicum with 1000 configs
Returns
- result (list[Obs]): list of Observables with length T, observable per timeslice. bb-type correlators have length 1.
def
read_sfcf_multi( path, prefix, name_list, quarks_list=['.*'], corr_type_list=['bi'], noffset_list=[0], wf_list=[0], wf2_list=[0], version='1.0c', cfg_separator='n', cfg_func=None, silent=False, keyed_out=False, **kwargs):
80def read_sfcf_multi(path, prefix, name_list, quarks_list=['.*'], corr_type_list=['bi'], noffset_list=[0], wf_list=[0], wf2_list=[0], version="1.0c", cfg_separator="n", cfg_func=None, silent=False, keyed_out=False, **kwargs): 81 """Read sfcf files from given folder structure. 82 83 Parameters 84 ---------- 85 path : str 86 Path to the sfcf files. 87 prefix : str 88 Prefix of the sfcf files. 89 name : str 90 Name of the correlation function to read. 91 quarks_list : list[str] 92 Label of the quarks used in the sfcf input file. e.g. "quark quark" 93 for version 0.0 this does NOT need to be given with the typical " - " 94 that is present in the output file, 95 this is done automatically for this version 96 corr_type_list : list[str] 97 Type of correlation function to read. Can be 98 - 'bi' for boundary-inner 99 - 'bb' for boundary-boundary 100 - 'bib' for boundary-inner-boundary 101 noffset_list : list[int] 102 Offset of the source (only relevant when wavefunctions are used) 103 wf_list : int 104 ID of wave function 105 wf2_list : list[int] 106 ID of the second wavefunction 107 (only relevant for boundary-to-boundary correlation functions) 108 im : bool 109 if True, read imaginary instead of real part 110 of the correlation function. 111 names : list 112 Alternative labeling for replicas/ensembles. 113 Has to have the appropriate length 114 ens_name : str 115 replaces the name of the ensemble 116 version: str 117 version of SFCF, with which the measurement was done. 118 if the compact output option (-c) was specified, 119 append a "c" to the version (e.g. "1.0c") 120 if the append output option (-a) was specified, 121 append an "a" to the version 122 cfg_separator : str 123 String that separates the ensemble identifier from the configuration number (default 'n'). 124 replica: list 125 list of replica to be read, default is all 126 files: list[list[int]] 127 list of files to be read per replica, default is all. 128 for non-compact output format, hand the folders to be read here. 129 check_configs: list[list[int]] 130 list of list of supposed configs, eg. [range(1,1000)] 131 for one replicum with 1000 configs 132 rep_string: str 133 Separator of ensemble name and replicum. Example: In "ensAr0", "r" would be the separator string. 134 Returns 135 ------- 136 result: dict[list[Obs]] 137 dict with one of the following properties: 138 if keyed_out: 139 dict[key] = list[Obs] 140 where key has the form name/quarks/offset/wf/wf2 141 if not keyed_out: 142 dict[name][quarks][offset][wf][wf2] = list[Obs] 143 """ 144 145 if kwargs.get('im'): 146 im = 1 147 part = 'imaginary' 148 else: 149 im = 0 150 part = 'real' 151 152 known_versions = ["0.0", "1.0", "2.0", "1.0c", "2.0c", "1.0a", "2.0a"] 153 154 if version not in known_versions: 155 raise Exception("This version is not known!") 156 if (version[-1] == "c"): 157 appended = False 158 compact = True 159 version = version[:-1] 160 elif (version[-1] == "a"): 161 appended = True 162 compact = False 163 version = version[:-1] 164 else: 165 compact = False 166 appended = False 167 ls = [] 168 if "replica" in kwargs: 169 ls = kwargs.get("replica") 170 else: 171 for (dirpath, dirnames, filenames) in os.walk(path): 172 if not appended: 173 ls.extend(dirnames) 174 else: 175 ls.extend(filenames) 176 break 177 if not ls: 178 raise Exception('Error, directory not found') 179 # Exclude folders with different names 180 for exc in ls: 181 if not fnmatch.fnmatch(exc, prefix + '*'): 182 ls = list(set(ls) - set([exc])) 183 184 if not appended: 185 ls = sort_names(ls) 186 replica = len(ls) 187 188 else: 189 replica = len([file.split(".")[-1] for file in ls]) // len(set([file.split(".")[-1] for file in ls])) 190 if replica == 0: 191 raise Exception('No replica found in directory') 192 if not silent: 193 print('Read', part, 'part of', name_list, 'from', prefix[:-1], ',', replica, 'replica') 194 195 if 'names' in kwargs: 196 new_names = kwargs.get('names') 197 if len(new_names) != len(set(new_names)): 198 raise Exception("names are not unique!") 199 if len(new_names) != replica: 200 raise Exception('names should have the length', replica) 201 202 else: 203 ens_name = kwargs.get("ens_name") 204 if not appended: 205 new_names = _get_rep_names(ls, ens_name, rep_sep=(kwargs.get('rep_string', 'r'))) 206 else: 207 new_names = _get_appended_rep_names(ls, prefix, name_list[0], ens_name, rep_sep=(kwargs.get('rep_string', 'r'))) 208 new_names = sort_names(new_names) 209 210 idl = [] 211 212 noffset_list = [str(x) for x in noffset_list] 213 wf_list = [str(x) for x in wf_list] 214 wf2_list = [str(x) for x in wf2_list] 215 216 # setup dict structures 217 intern = {} 218 for name, corr_type in zip(name_list, corr_type_list): 219 intern[name] = {} 220 b2b, single = _extract_corr_type(corr_type) 221 intern[name]["b2b"] = b2b 222 intern[name]["single"] = single 223 intern[name]["spec"] = {} 224 for quarks in quarks_list: 225 intern[name]["spec"][quarks] = {} 226 for off in noffset_list: 227 intern[name]["spec"][quarks][off] = {} 228 for w in wf_list: 229 intern[name]["spec"][quarks][off][w] = {} 230 if b2b: 231 for w2 in wf2_list: 232 intern[name]["spec"][quarks][off][w][w2] = {} 233 intern[name]["spec"][quarks][off][w][w2]["pattern"] = _make_pattern(version, name, off, w, w2, intern[name]['b2b'], quarks) 234 else: 235 intern[name]["spec"][quarks][off][w]["0"] = {} 236 intern[name]["spec"][quarks][off][w]["0"]["pattern"] = _make_pattern(version, name, off, w, 0, intern[name]['b2b'], quarks) 237 238 internal_ret_dict = {} 239 needed_keys = [] 240 for name, corr_type in zip(name_list, corr_type_list): 241 b2b, single = _extract_corr_type(corr_type) 242 if b2b: 243 needed_keys.extend(_lists2key([name], quarks_list, noffset_list, wf_list, wf2_list)) 244 else: 245 needed_keys.extend(_lists2key([name], quarks_list, noffset_list, wf_list, ["0"])) 246 247 for key in needed_keys: 248 internal_ret_dict[key] = [] 249 250 def _default_idl_func(cfg_string, cfg_sep): 251 return int(cfg_string.split(cfg_sep)[-1]) 252 253 if cfg_func is None: 254 print("Default idl function in use.") 255 cfg_func = _default_idl_func 256 cfg_func_args = [cfg_separator] 257 else: 258 cfg_func_args = kwargs.get("cfg_func_args", []) 259 260 if not appended: 261 for i, item in enumerate(ls): 262 rep_path = path + '/' + item 263 if "files" in kwargs: 264 files = kwargs.get("files") 265 if isinstance(files, list): 266 if all(isinstance(f, list) for f in files): 267 files = files[i] 268 elif all(isinstance(f, str) for f in files): 269 files = files 270 else: 271 raise TypeError("files has to be of type list[list[str]] or list[str]!") 272 else: 273 raise TypeError("files has to be of type list[list[str]] or list[str]!") 274 275 else: 276 files = [] 277 sub_ls = _find_files(rep_path, prefix, compact, files) 278 rep_idl = [] 279 no_cfg = len(sub_ls) 280 for cfg in sub_ls: 281 try: 282 if compact: 283 rep_idl.append(cfg_func(cfg, *cfg_func_args)) 284 else: 285 rep_idl.append(int(cfg[3:])) 286 except Exception: 287 raise Exception("Couldn't parse idl from directory, problem with file " + cfg) 288 rep_idl.sort() 289 # maybe there is a better way to print the idls 290 if not silent: 291 print(item, ':', no_cfg, ' configurations') 292 idl.append(rep_idl) 293 # here we have found all the files we need to look into. 294 if i == 0: 295 if version != "0.0" and compact: 296 file = path + '/' + item + '/' + sub_ls[0] 297 for name_index, name in enumerate(name_list): 298 if version == "0.0" or not compact: 299 file = path + '/' + item + '/' + sub_ls[0] + '/' + name 300 if corr_type_list[name_index] == 'bi': 301 name_keys = _lists2key(quarks_list, noffset_list, wf_list, ["0"]) 302 else: 303 name_keys = _lists2key(quarks_list, noffset_list, wf_list, wf2_list) 304 for key in name_keys: 305 specs = _key2specs(key) 306 quarks = specs[0] 307 off = specs[1] 308 w = specs[2] 309 w2 = specs[3] 310 # here, we want to find the place within the file, 311 # where the correlator we need is stored. 312 # to do so, the pattern needed is put together 313 # from the input values 314 start_read, T = _find_correlator(file, version, intern[name]["spec"][quarks][str(off)][str(w)][str(w2)]["pattern"], intern[name]['b2b'], silent=silent) 315 intern[name]["spec"][quarks][str(off)][str(w)][str(w2)]["start"] = start_read 316 intern[name]["T"] = T 317 # preparing the datastructure 318 # the correlators get parsed into... 319 deltas = [] 320 for j in range(intern[name]["T"]): 321 deltas.append([]) 322 internal_ret_dict[sep.join([name, key])] = deltas 323 324 if compact: 325 rep_deltas = _read_compact_rep(path, item, sub_ls, intern, needed_keys, im) 326 for key in needed_keys: 327 name = _key2specs(key)[0] 328 for t in range(intern[name]["T"]): 329 internal_ret_dict[key][t].append(rep_deltas[key][t]) 330 else: 331 for key in needed_keys: 332 rep_data = [] 333 name = _key2specs(key)[0] 334 for subitem in sub_ls: 335 cfg_path = path + '/' + item + '/' + subitem 336 file_data = _read_o_file(cfg_path, name, needed_keys, intern, version, im) 337 rep_data.append(file_data) 338 for t in range(intern[name]["T"]): 339 internal_ret_dict[key][t].append([]) 340 for cfg in range(no_cfg): 341 internal_ret_dict[key][t][i].append(rep_data[cfg][key][t]) 342 else: 343 for key in needed_keys: 344 specs = _key2specs(key) 345 name = specs[0] 346 quarks = specs[1] 347 off = specs[2] 348 w = specs[3] 349 w2 = specs[4] 350 if "files" in kwargs: 351 if isinstance(kwargs.get("files"), list) and all(isinstance(f, str) for f in kwargs.get("files")): 352 name_ls = kwargs.get("files") 353 else: 354 raise TypeError("In append mode, files has to be of type list[str]!") 355 else: 356 name_ls = ls 357 for exc in name_ls: 358 if not fnmatch.fnmatch(exc, prefix + '*.' + name): 359 name_ls = list(set(name_ls) - set([exc])) 360 name_ls = sort_names(name_ls) 361 pattern = intern[name]['spec'][quarks][off][w][w2]['pattern'] 362 deltas = [] 363 for rep, file in enumerate(name_ls): 364 rep_idl = [] 365 filename = path + '/' + file 366 T, rep_idl, rep_data = _read_append_rep(filename, pattern, intern[name]['b2b'], im, intern[name]['single'], cfg_func, cfg_func_args) 367 if rep == 0: 368 intern[name]['T'] = T 369 for t in range(intern[name]['T']): 370 deltas.append([]) 371 for t in range(intern[name]['T']): 372 deltas[t].append(rep_data[t]) 373 internal_ret_dict[key] = deltas 374 if name == name_list[0]: 375 idl.append(rep_idl) 376 377 if kwargs.get("check_configs") is True: 378 if not silent: 379 print("Checking for missing configs...") 380 che = kwargs.get("check_configs") 381 if not (len(che) == len(idl)): 382 raise Exception("check_configs has to be the same length as replica!") 383 for r in range(len(idl)): 384 if not silent: 385 print("checking " + new_names[r]) 386 check_idl(idl[r], che[r]) 387 if not silent: 388 print("Done") 389 390 result_dict = {} 391 if keyed_out: 392 for key in needed_keys: 393 name = _key2specs(key)[0] 394 result = [] 395 for t in range(intern[name]["T"]): 396 result.append(Obs(internal_ret_dict[key][t], new_names, idl=idl)) 397 result_dict[key] = result 398 else: 399 for name, corr_type in zip(name_list, corr_type_list): 400 result_dict[name] = {} 401 for quarks in quarks_list: 402 result_dict[name][quarks] = {} 403 for off in noffset_list: 404 result_dict[name][quarks][off] = {} 405 for w in wf_list: 406 result_dict[name][quarks][off][w] = {} 407 if corr_type != 'bi': 408 for w2 in wf2_list: 409 key = _specs2key(name, quarks, off, w, w2) 410 result = [] 411 for t in range(intern[name]["T"]): 412 result.append(Obs(internal_ret_dict[key][t], new_names, idl=idl)) 413 result_dict[name][quarks][str(off)][str(w)][str(w2)] = result 414 else: 415 key = _specs2key(name, quarks, off, w, "0") 416 result = [] 417 for t in range(intern[name]["T"]): 418 result.append(Obs(internal_ret_dict[key][t], new_names, idl=idl)) 419 result_dict[name][quarks][str(off)][str(w)][str(0)] = result 420 return result_dict
Read sfcf files from given folder structure.
Parameters
- path (str): Path to the sfcf files.
- prefix (str): Prefix of the sfcf files.
- name (str): Name of the correlation function to read.
- quarks_list (list[str]): Label of the quarks used in the sfcf input file. e.g. "quark quark" for version 0.0 this does NOT need to be given with the typical " - " that is present in the output file, this is done automatically for this version
- corr_type_list (list[str]):
Type of correlation function to read. Can be
- 'bi' for boundary-inner
- 'bb' for boundary-boundary
- 'bib' for boundary-inner-boundary
- noffset_list (list[int]): Offset of the source (only relevant when wavefunctions are used)
- wf_list (int): ID of wave function
- wf2_list (list[int]): ID of the second wavefunction (only relevant for boundary-to-boundary correlation functions)
- im (bool): if True, read imaginary instead of real part of the correlation function.
- names (list): Alternative labeling for replicas/ensembles. Has to have the appropriate length
- ens_name (str): replaces the name of the ensemble
- version (str): version of SFCF, with which the measurement was done. if the compact output option (-c) was specified, append a "c" to the version (e.g. "1.0c") if the append output option (-a) was specified, append an "a" to the version
- cfg_separator (str): String that separates the ensemble identifier from the configuration number (default 'n').
- replica (list): list of replica to be read, default is all
- files (list[list[int]]): list of files to be read per replica, default is all. for non-compact output format, hand the folders to be read here.
- check_configs (list[list[int]]): list of list of supposed configs, eg. [range(1,1000)] for one replicum with 1000 configs
- rep_string (str): Separator of ensemble name and replicum. Example: In "ensAr0", "r" would be the separator string.
Returns
- result (dict[list[Obs]]): dict with one of the following properties: if keyed_out: dict[key] = list[Obs] where key has the form name/quarks/offset/wf/wf2 if not keyed_out: dict[name][quarks][offset][wf][wf2] = list[Obs]