# pyerrors.input.sfcf API documentation

# pyerrors.input.sfcf

View Source

      1import os
      2import fnmatch
      3import re
      4import numpy as np  # Thinly-wrapped numpy
      5from ..obs import Obs
      6from . import utils
      7
      8
      9def read_sfcf(path, prefix, name, quarks='.*', corr_type='bi', noffset=0, wf=0, wf2=0, version="1.0c", cfg_separator="n", **kwargs):
     10    """Read sfcf c format from given folder structure.
     11
     12    Parameters
     13    ----------
     14    path : str
     15        Path to the sfcf files.
     16    prefix : str
     17        Prefix of the sfcf files.
     18    name : str
     19        Name of the correlation function to read.
     20    quarks : str
     21        Label of the quarks used in the sfcf input file. e.g. "quark quark"
     22        for version 0.0 this does NOT need to be given with the typical " - "
     23        that is present in the output file,
     24        this is done automatically for this version
     25    corr_type : str
     26        Type of correlation function to read. Can be
     27        - 'bi' for boundary-inner
     28        - 'bb' for boundary-boundary
     29        - 'bib' for boundary-inner-boundary
     30    noffset : int
     31        Offset of the source (only relevant when wavefunctions are used)
     32    wf : int
     33        ID of wave function
     34    wf2 : int
     35        ID of the second wavefunction
     36        (only relevant for boundary-to-boundary correlation functions)
     37    im : bool
     38        if True, read imaginary instead of real part
     39        of the correlation function.
     40    names : list
     41        Alternative labeling for replicas/ensembles.
     42        Has to have the appropriate length
     43    ens_name : str
     44        replaces the name of the ensemble
     45    version: str
     46        version of SFCF, with which the measurement was done.
     47        if the compact output option (-c) was specified,
     48        append a "c" to the version (e.g. "1.0c")
     49        if the append output option (-a) was specified,
     50        append an "a" to the version
     51    cfg_separator : str
     52        String that separates the ensemble identifier from the configuration number (default 'n').
     53    replica: list
     54        list of replica to be read, default is all
     55    files: list
     56        list of files to be read per replica, default is all.
     57        for non-compact output format, hand the folders to be read here.
     58    check_configs: list[list[int]]
     59        list of list of supposed configs, eg. [range(1,1000)]
     60        for one replicum with 1000 configs
     61
     62    Returns
     63    -------
     64    result: list[Obs]
     65        list of Observables with length T, observable per timeslice.
     66        bb-type correlators have length 1.
     67    """
     68    if kwargs.get('im'):
     69        im = 1
     70        part = 'imaginary'
     71    else:
     72        im = 0
     73        part = 'real'
     74    if "replica" in kwargs:
     75        reps = kwargs.get("replica")
     76    if corr_type == 'bb':
     77        b2b = True
     78        single = True
     79    elif corr_type == 'bib':
     80        b2b = True
     81        single = False
     82    else:
     83        b2b = False
     84        single = False
     85    compact = True
     86    appended = False
     87    known_versions = ["0.0", "1.0", "2.0", "1.0c", "2.0c", "1.0a", "2.0a"]
     88
     89    if version not in known_versions:
     90        raise Exception("This version is not known!")
     91    if (version[-1] == "c"):
     92        appended = False
     93        compact = True
     94        version = version[:-1]
     95    elif (version[-1] == "a"):
     96        appended = True
     97        compact = False
     98        version = version[:-1]
     99    else:
    100        compact = False
    101        appended = False
    102    read = 0
    103    T = 0
    104    start = 0
    105    ls = []
    106    if "replica" in kwargs:
    107        ls = reps
    108    else:
    109        for (dirpath, dirnames, filenames) in os.walk(path):
    110            if not appended:
    111                ls.extend(dirnames)
    112            else:
    113                ls.extend(filenames)
    114            break
    115        if not ls:
    116            raise Exception('Error, directory not found')
    117        # Exclude folders with different names
    118        for exc in ls:
    119            if not fnmatch.fnmatch(exc, prefix + '*'):
    120                ls = list(set(ls) - set([exc]))
    121
    122    if not appended:
    123        if len(ls) > 1:
    124            # New version, to cope with ids, etc.
    125            ls.sort(key=lambda x: int(re.findall(r'\d+', x[len(prefix):])[0]))
    126        replica = len(ls)
    127    else:
    128        replica = len([file.split(".")[-1] for file in ls]) // len(set([file.split(".")[-1] for file in ls]))
    129    print('Read', part, 'part of', name, 'from', prefix[:-1],
    130          ',', replica, 'replica')
    131    if 'names' in kwargs:
    132        new_names = kwargs.get('names')
    133        if len(new_names) != len(set(new_names)):
    134            raise Exception("names are not unique!")
    135        if len(new_names) != replica:
    136            raise Exception('Names does not have the required length', replica)
    137    else:
    138        new_names = []
    139        if not appended:
    140            for entry in ls:
    141                try:
    142                    idx = entry.index('r')
    143                except Exception:
    144                    raise Exception("Automatic recognition of replicum failed, please enter the key word 'names'.")
    145
    146                if 'ens_name' in kwargs:
    147                    new_names.append(kwargs.get('ens_name') + '|' + entry[idx:])
    148                else:
    149                    new_names.append(entry[:idx] + '|' + entry[idx:])
    150        else:
    151
    152            for exc in ls:
    153                if not fnmatch.fnmatch(exc, prefix + '*.' + name):
    154                    ls = list(set(ls) - set([exc]))
    155            ls.sort(key=lambda x: int(re.findall(r'\d+', x)[-1]))
    156            for entry in ls:
    157                myentry = entry[:-len(name) - 1]
    158                try:
    159                    idx = myentry.index('r')
    160                except Exception:
    161                    raise Exception("Automatic recognition of replicum failed, please enter the key word 'names'.")
    162
    163                if 'ens_name' in kwargs:
    164                    new_names.append(kwargs.get('ens_name') + '|' + myentry[idx:])
    165                else:
    166                    new_names.append(myentry[:idx] + '|' + myentry[idx:])
    167    idl = []
    168    if not appended:
    169        for i, item in enumerate(ls):
    170            sub_ls = []
    171            if "files" in kwargs:
    172                sub_ls = kwargs.get("files")
    173                sub_ls.sort(key=lambda x: int(re.findall(r'\d+', x)[-1]))
    174            else:
    175                for (dirpath, dirnames, filenames) in os.walk(path + '/' + item):
    176                    if compact:
    177                        sub_ls.extend(filenames)
    178                    else:
    179                        sub_ls.extend(dirnames)
    180                    break
    181                if compact:
    182                    for exc in sub_ls:
    183                        if not fnmatch.fnmatch(exc, prefix + '*'):
    184                            sub_ls = list(set(sub_ls) - set([exc]))
    185                    sub_ls.sort(key=lambda x: int(re.findall(r'\d+', x)[-1]))
    186                else:
    187                    for exc in sub_ls:
    188                        if not fnmatch.fnmatch(exc, 'cfg*'):
    189                            sub_ls = list(set(sub_ls) - set([exc]))
    190                    sub_ls.sort(key=lambda x: int(x[3:]))
    191            rep_idl = []
    192            no_cfg = len(sub_ls)
    193            for cfg in sub_ls:
    194                try:
    195                    if compact:
    196                        rep_idl.append(int(cfg.split(cfg_separator)[-1]))
    197                    else:
    198                        rep_idl.append(int(cfg[3:]))
    199                except Exception:
    200                    raise Exception("Couldn't parse idl from directroy, problem with file " + cfg)
    201            rep_idl.sort()
    202            # maybe there is a better way to print the idls
    203            print(item, ':', no_cfg, ' configurations')
    204            idl.append(rep_idl)
    205            # here we have found all the files we need to look into.
    206            if i == 0:
    207                # here, we want to find the place within the file,
    208                # where the correlator we need is stored.
    209                # to do so, the pattern needed is put together
    210                # from the input values
    211                if version == "0.0":
    212                    pattern = "# " + name + " : offset " + str(noffset) + ", wf " + str(wf)
    213                    # if b2b, a second wf is needed
    214                    if b2b:
    215                        pattern += ", wf_2 " + str(wf2)
    216                    qs = quarks.split(" ")
    217                    pattern += " : " + qs[0] + " - " + qs[1]
    218                    file = open(path + '/' + item + '/' + sub_ls[0] + '/' + name, "r")
    219                    for k, line in enumerate(file):
    220                        if read == 1 and not line.strip() and k > start + 1:
    221                            break
    222                        if read == 1 and k >= start:
    223                            T += 1
    224                        if pattern in line:
    225                            read = 1
    226                            start = k + 1
    227                    print(str(T) + " entries found.")
    228                    file.close()
    229                else:
    230                    pattern = 'name      ' + name + '\nquarks    ' + quarks + '\noffset    ' + str(noffset) + '\nwf        ' + str(wf)
    231                    if b2b:
    232                        pattern += '\nwf_2      ' + str(wf2)
    233                    # and the file is parsed through to find the pattern
    234                    if compact:
    235                        file = open(path + '/' + item + '/' + sub_ls[0], "r")
    236                    else:
    237                        # for non-compactified versions of the files
    238                        file = open(path + '/' + item + '/' + sub_ls[0] + '/' + name, "r")
    239
    240                    content = file.read()
    241                    match = re.search(pattern, content)
    242                    if match:
    243                        start_read = content.count('\n', 0, match.start()) + 5 + b2b
    244                        end_match = re.search(r'\n\s*\n', content[match.start():])
    245                        T = content[match.start():].count('\n', 0, end_match.start()) - 4 - b2b
    246                        assert T > 0
    247                        print(T, 'entries, starting to read in line', start_read)
    248                        file.close()
    249                    else:
    250                        file.close()
    251                        raise Exception('Correlator with pattern\n' + pattern + '\nnot found.')
    252
    253                # we found where the correlator
    254                # that is to be read is in the files
    255                # after preparing the datastructure
    256                # the correlators get parsed into...
    257                deltas = []
    258                for j in range(T):
    259                    deltas.append([])
    260
    261            for t in range(T):
    262                deltas[t].append(np.zeros(no_cfg))
    263            if compact:
    264                for cfg in range(no_cfg):
    265                    with open(path + '/' + item + '/' + sub_ls[cfg]) as fp:
    266                        lines = fp.readlines()
    267                        # check, if the correlator is in fact
    268                        # printed completely
    269                        if (start_read + T > len(lines)):
    270                            raise Exception("EOF before end of correlator data! Maybe " + path + '/' + item + '/' + sub_ls[cfg] + " is corrupted?")
    271                        # and start to read the correlator.
    272                        # the range here is chosen like this,
    273                        # since this allows for implementing
    274                        # a security check for every read correlator later...
    275                        for k in range(start_read - 6, start_read + T):
    276                            if k == start_read - 5 - b2b:
    277                                if lines[k].strip() != 'name      ' + name:
    278                                    raise Exception('Wrong format', sub_ls[cfg])
    279                            if (k >= start_read and k < start_read + T):
    280                                floats = list(map(float, lines[k].split()))
    281                                deltas[k - start_read][i][cfg] = floats[-2:][im]
    282            else:
    283                for cnfg, subitem in enumerate(sub_ls):
    284                    with open(path + '/' + item + '/' + subitem + '/' + name) as fp:
    285                        # since the non-compatified files
    286                        # are typically not so long,
    287                        # we can iterate over the whole file.
    288                        # here one can also implement the chekc from above.
    289                        for k, line in enumerate(fp):
    290                            if (k >= start_read and k < start_read + T):
    291                                floats = list(map(float, line.split()))
    292                                if version == "0.0":
    293                                    deltas[k - start][i][cnfg] = floats[im - single]
    294                                else:
    295                                    deltas[k - start_read][i][cnfg] = floats[1 + im - single]
    296
    297    else:
    298        if "files" in kwargs:
    299            ls = kwargs.get("files")
    300        else:
    301            for exc in ls:
    302                if not fnmatch.fnmatch(exc, prefix + '*.' + name):
    303                    ls = list(set(ls) - set([exc]))
    304                ls.sort(key=lambda x: int(re.findall(r'\d+', x)[-1]))
    305        pattern = 'name      ' + name + '\nquarks    ' + quarks + '\noffset    ' + str(noffset) + '\nwf        ' + str(wf)
    306        if b2b:
    307            pattern += '\nwf_2      ' + str(wf2)
    308        for rep, file in enumerate(ls):
    309            rep_idl = []
    310            with open(path + '/' + file, 'r') as fp:
    311                content = fp.readlines()
    312                data_starts = []
    313                for linenumber, line in enumerate(content):
    314                    if "[run]" in line:
    315                        data_starts.append(linenumber)
    316                if len(set([data_starts[i] - data_starts[i - 1] for i in range(1, len(data_starts))])) > 1:
    317                    raise Exception("Irregularities in file structure found, not all runs have the same output length")
    318                chunk = content[:data_starts[1]]
    319                for linenumber, line in enumerate(chunk):
    320                    if line.startswith("gauge_name"):
    321                        gauge_line = linenumber
    322                    elif line.startswith("[correlator]"):
    323                        corr_line = linenumber
    324                        found_pat = ""
    325                        for li in chunk[corr_line + 1: corr_line + 6 + b2b]:
    326                            found_pat += li
    327                        if re.search(pattern, found_pat):
    328                            start_read = corr_line + 7 + b2b
    329                            break
    330                endline = corr_line + 6 + b2b
    331                while not chunk[endline] == "\n":
    332                    endline += 1
    333                T = endline - start_read
    334                if rep == 0:
    335                    deltas = []
    336                    for t in range(T):
    337                        deltas.append([])
    338                for t in range(T):
    339                    deltas[t].append(np.zeros(len(data_starts)))
    340                # all other chunks should follow the same structure
    341                for cnfg in range(len(data_starts)):
    342                    start = data_starts[cnfg]
    343                    stop = start + data_starts[1]
    344                    chunk = content[start:stop]
    345                    try:
    346                        rep_idl.append(int(chunk[gauge_line].split(cfg_separator)[-1]))
    347                    except Exception:
    348                        raise Exception("Couldn't parse idl from directory, problem with chunk around line ", gauge_line)
    349
    350                    found_pat = ""
    351                    for li in chunk[corr_line + 1:corr_line + 6 + b2b]:
    352                        found_pat += li
    353                    if re.search(pattern, found_pat):
    354                        for t, line in enumerate(chunk[start_read:start_read + T]):
    355                            floats = list(map(float, line.split()))
    356                            deltas[t][rep][cnfg] = floats[im + 1 - single]
    357            idl.append(rep_idl)
    358
    359    if "check_configs" in kwargs:
    360        print("Checking for missing configs...")
    361        che = kwargs.get("check_configs")
    362        if not (len(che) == len(idl)):
    363            raise Exception("check_configs has to be the same length as replica!")
    364        for r in range(len(idl)):
    365            print("checking " + new_names[r])
    366            utils.check_idl(idl[r], che[r])
    367        print("Done")
    368    result = []
    369    for t in range(T):
    370        result.append(Obs(deltas[t], new_names, idl=idl))
    371    return result

def read_sfcf( path, prefix, name, quarks='.*', corr_type='bi', noffset=0, wf=0, wf2=0, version='1.0c', cfg_separator='n', **kwargs): View Source

     10def read_sfcf(path, prefix, name, quarks='.*', corr_type='bi', noffset=0, wf=0, wf2=0, version="1.0c", cfg_separator="n", **kwargs):
     11    """Read sfcf c format from given folder structure.
     12
     13    Parameters
     14    ----------
     15    path : str
     16        Path to the sfcf files.
     17    prefix : str
     18        Prefix of the sfcf files.
     19    name : str
     20        Name of the correlation function to read.
     21    quarks : str
     22        Label of the quarks used in the sfcf input file. e.g. "quark quark"
     23        for version 0.0 this does NOT need to be given with the typical " - "
     24        that is present in the output file,
     25        this is done automatically for this version
     26    corr_type : str
     27        Type of correlation function to read. Can be
     28        - 'bi' for boundary-inner
     29        - 'bb' for boundary-boundary
     30        - 'bib' for boundary-inner-boundary
     31    noffset : int
     32        Offset of the source (only relevant when wavefunctions are used)
     33    wf : int
     34        ID of wave function
     35    wf2 : int
     36        ID of the second wavefunction
     37        (only relevant for boundary-to-boundary correlation functions)
     38    im : bool
     39        if True, read imaginary instead of real part
     40        of the correlation function.
     41    names : list
     42        Alternative labeling for replicas/ensembles.
     43        Has to have the appropriate length
     44    ens_name : str
     45        replaces the name of the ensemble
     46    version: str
     47        version of SFCF, with which the measurement was done.
     48        if the compact output option (-c) was specified,
     49        append a "c" to the version (e.g. "1.0c")
     50        if the append output option (-a) was specified,
     51        append an "a" to the version
     52    cfg_separator : str
     53        String that separates the ensemble identifier from the configuration number (default 'n').
     54    replica: list
     55        list of replica to be read, default is all
     56    files: list
     57        list of files to be read per replica, default is all.
     58        for non-compact output format, hand the folders to be read here.
     59    check_configs: list[list[int]]
     60        list of list of supposed configs, eg. [range(1,1000)]
     61        for one replicum with 1000 configs
     62
     63    Returns
     64    -------
     65    result: list[Obs]
     66        list of Observables with length T, observable per timeslice.
     67        bb-type correlators have length 1.
     68    """
     69    if kwargs.get('im'):
     70        im = 1
     71        part = 'imaginary'
     72    else:
     73        im = 0
     74        part = 'real'
     75    if "replica" in kwargs:
     76        reps = kwargs.get("replica")
     77    if corr_type == 'bb':
     78        b2b = True
     79        single = True
     80    elif corr_type == 'bib':
     81        b2b = True
     82        single = False
     83    else:
     84        b2b = False
     85        single = False
     86    compact = True
     87    appended = False
     88    known_versions = ["0.0", "1.0", "2.0", "1.0c", "2.0c", "1.0a", "2.0a"]
     89
     90    if version not in known_versions:
     91        raise Exception("This version is not known!")
     92    if (version[-1] == "c"):
     93        appended = False
     94        compact = True
     95        version = version[:-1]
     96    elif (version[-1] == "a"):
     97        appended = True
     98        compact = False
     99        version = version[:-1]
    100    else:
    101        compact = False
    102        appended = False
    103    read = 0
    104    T = 0
    105    start = 0
    106    ls = []
    107    if "replica" in kwargs:
    108        ls = reps
    109    else:
    110        for (dirpath, dirnames, filenames) in os.walk(path):
    111            if not appended:
    112                ls.extend(dirnames)
    113            else:
    114                ls.extend(filenames)
    115            break
    116        if not ls:
    117            raise Exception('Error, directory not found')
    118        # Exclude folders with different names
    119        for exc in ls:
    120            if not fnmatch.fnmatch(exc, prefix + '*'):
    121                ls = list(set(ls) - set([exc]))
    122
    123    if not appended:
    124        if len(ls) > 1:
    125            # New version, to cope with ids, etc.
    126            ls.sort(key=lambda x: int(re.findall(r'\d+', x[len(prefix):])[0]))
    127        replica = len(ls)
    128    else:
    129        replica = len([file.split(".")[-1] for file in ls]) // len(set([file.split(".")[-1] for file in ls]))
    130    print('Read', part, 'part of', name, 'from', prefix[:-1],
    131          ',', replica, 'replica')
    132    if 'names' in kwargs:
    133        new_names = kwargs.get('names')
    134        if len(new_names) != len(set(new_names)):
    135            raise Exception("names are not unique!")
    136        if len(new_names) != replica:
    137            raise Exception('Names does not have the required length', replica)
    138    else:
    139        new_names = []
    140        if not appended:
    141            for entry in ls:
    142                try:
    143                    idx = entry.index('r')
    144                except Exception:
    145                    raise Exception("Automatic recognition of replicum failed, please enter the key word 'names'.")
    146
    147                if 'ens_name' in kwargs:
    148                    new_names.append(kwargs.get('ens_name') + '|' + entry[idx:])
    149                else:
    150                    new_names.append(entry[:idx] + '|' + entry[idx:])
    151        else:
    152
    153            for exc in ls:
    154                if not fnmatch.fnmatch(exc, prefix + '*.' + name):
    155                    ls = list(set(ls) - set([exc]))
    156            ls.sort(key=lambda x: int(re.findall(r'\d+', x)[-1]))
    157            for entry in ls:
    158                myentry = entry[:-len(name) - 1]
    159                try:
    160                    idx = myentry.index('r')
    161                except Exception:
    162                    raise Exception("Automatic recognition of replicum failed, please enter the key word 'names'.")
    163
    164                if 'ens_name' in kwargs:
    165                    new_names.append(kwargs.get('ens_name') + '|' + myentry[idx:])
    166                else:
    167                    new_names.append(myentry[:idx] + '|' + myentry[idx:])
    168    idl = []
    169    if not appended:
    170        for i, item in enumerate(ls):
    171            sub_ls = []
    172            if "files" in kwargs:
    173                sub_ls = kwargs.get("files")
    174                sub_ls.sort(key=lambda x: int(re.findall(r'\d+', x)[-1]))
    175            else:
    176                for (dirpath, dirnames, filenames) in os.walk(path + '/' + item):
    177                    if compact:
    178                        sub_ls.extend(filenames)
    179                    else:
    180                        sub_ls.extend(dirnames)
    181                    break
    182                if compact:
    183                    for exc in sub_ls:
    184                        if not fnmatch.fnmatch(exc, prefix + '*'):
    185                            sub_ls = list(set(sub_ls) - set([exc]))
    186                    sub_ls.sort(key=lambda x: int(re.findall(r'\d+', x)[-1]))
    187                else:
    188                    for exc in sub_ls:
    189                        if not fnmatch.fnmatch(exc, 'cfg*'):
    190                            sub_ls = list(set(sub_ls) - set([exc]))
    191                    sub_ls.sort(key=lambda x: int(x[3:]))
    192            rep_idl = []
    193            no_cfg = len(sub_ls)
    194            for cfg in sub_ls:
    195                try:
    196                    if compact:
    197                        rep_idl.append(int(cfg.split(cfg_separator)[-1]))
    198                    else:
    199                        rep_idl.append(int(cfg[3:]))
    200                except Exception:
    201                    raise Exception("Couldn't parse idl from directroy, problem with file " + cfg)
    202            rep_idl.sort()
    203            # maybe there is a better way to print the idls
    204            print(item, ':', no_cfg, ' configurations')
    205            idl.append(rep_idl)
    206            # here we have found all the files we need to look into.
    207            if i == 0:
    208                # here, we want to find the place within the file,
    209                # where the correlator we need is stored.
    210                # to do so, the pattern needed is put together
    211                # from the input values
    212                if version == "0.0":
    213                    pattern = "# " + name + " : offset " + str(noffset) + ", wf " + str(wf)
    214                    # if b2b, a second wf is needed
    215                    if b2b:
    216                        pattern += ", wf_2 " + str(wf2)
    217                    qs = quarks.split(" ")
    218                    pattern += " : " + qs[0] + " - " + qs[1]
    219                    file = open(path + '/' + item + '/' + sub_ls[0] + '/' + name, "r")
    220                    for k, line in enumerate(file):
    221                        if read == 1 and not line.strip() and k > start + 1:
    222                            break
    223                        if read == 1 and k >= start:
    224                            T += 1
    225                        if pattern in line:
    226                            read = 1
    227                            start = k + 1
    228                    print(str(T) + " entries found.")
    229                    file.close()
    230                else:
    231                    pattern = 'name      ' + name + '\nquarks    ' + quarks + '\noffset    ' + str(noffset) + '\nwf        ' + str(wf)
    232                    if b2b:
    233                        pattern += '\nwf_2      ' + str(wf2)
    234                    # and the file is parsed through to find the pattern
    235                    if compact:
    236                        file = open(path + '/' + item + '/' + sub_ls[0], "r")
    237                    else:
    238                        # for non-compactified versions of the files
    239                        file = open(path + '/' + item + '/' + sub_ls[0] + '/' + name, "r")
    240
    241                    content = file.read()
    242                    match = re.search(pattern, content)
    243                    if match:
    244                        start_read = content.count('\n', 0, match.start()) + 5 + b2b
    245                        end_match = re.search(r'\n\s*\n', content[match.start():])
    246                        T = content[match.start():].count('\n', 0, end_match.start()) - 4 - b2b
    247                        assert T > 0
    248                        print(T, 'entries, starting to read in line', start_read)
    249                        file.close()
    250                    else:
    251                        file.close()
    252                        raise Exception('Correlator with pattern\n' + pattern + '\nnot found.')
    253
    254                # we found where the correlator
    255                # that is to be read is in the files
    256                # after preparing the datastructure
    257                # the correlators get parsed into...
    258                deltas = []
    259                for j in range(T):
    260                    deltas.append([])
    261
    262            for t in range(T):
    263                deltas[t].append(np.zeros(no_cfg))
    264            if compact:
    265                for cfg in range(no_cfg):
    266                    with open(path + '/' + item + '/' + sub_ls[cfg]) as fp:
    267                        lines = fp.readlines()
    268                        # check, if the correlator is in fact
    269                        # printed completely
    270                        if (start_read + T > len(lines)):
    271                            raise Exception("EOF before end of correlator data! Maybe " + path + '/' + item + '/' + sub_ls[cfg] + " is corrupted?")
    272                        # and start to read the correlator.
    273                        # the range here is chosen like this,
    274                        # since this allows for implementing
    275                        # a security check for every read correlator later...
    276                        for k in range(start_read - 6, start_read + T):
    277                            if k == start_read - 5 - b2b:
    278                                if lines[k].strip() != 'name      ' + name:
    279                                    raise Exception('Wrong format', sub_ls[cfg])
    280                            if (k >= start_read and k < start_read + T):
    281                                floats = list(map(float, lines[k].split()))
    282                                deltas[k - start_read][i][cfg] = floats[-2:][im]
    283            else:
    284                for cnfg, subitem in enumerate(sub_ls):
    285                    with open(path + '/' + item + '/' + subitem + '/' + name) as fp:
    286                        # since the non-compatified files
    287                        # are typically not so long,
    288                        # we can iterate over the whole file.
    289                        # here one can also implement the chekc from above.
    290                        for k, line in enumerate(fp):
    291                            if (k >= start_read and k < start_read + T):
    292                                floats = list(map(float, line.split()))
    293                                if version == "0.0":
    294                                    deltas[k - start][i][cnfg] = floats[im - single]
    295                                else:
    296                                    deltas[k - start_read][i][cnfg] = floats[1 + im - single]
    297
    298    else:
    299        if "files" in kwargs:
    300            ls = kwargs.get("files")
    301        else:
    302            for exc in ls:
    303                if not fnmatch.fnmatch(exc, prefix + '*.' + name):
    304                    ls = list(set(ls) - set([exc]))
    305                ls.sort(key=lambda x: int(re.findall(r'\d+', x)[-1]))
    306        pattern = 'name      ' + name + '\nquarks    ' + quarks + '\noffset    ' + str(noffset) + '\nwf        ' + str(wf)
    307        if b2b:
    308            pattern += '\nwf_2      ' + str(wf2)
    309        for rep, file in enumerate(ls):
    310            rep_idl = []
    311            with open(path + '/' + file, 'r') as fp:
    312                content = fp.readlines()
    313                data_starts = []
    314                for linenumber, line in enumerate(content):
    315                    if "[run]" in line:
    316                        data_starts.append(linenumber)
    317                if len(set([data_starts[i] - data_starts[i - 1] for i in range(1, len(data_starts))])) > 1:
    318                    raise Exception("Irregularities in file structure found, not all runs have the same output length")
    319                chunk = content[:data_starts[1]]
    320                for linenumber, line in enumerate(chunk):
    321                    if line.startswith("gauge_name"):
    322                        gauge_line = linenumber
    323                    elif line.startswith("[correlator]"):
    324                        corr_line = linenumber
    325                        found_pat = ""
    326                        for li in chunk[corr_line + 1: corr_line + 6 + b2b]:
    327                            found_pat += li
    328                        if re.search(pattern, found_pat):
    329                            start_read = corr_line + 7 + b2b
    330                            break
    331                endline = corr_line + 6 + b2b
    332                while not chunk[endline] == "\n":
    333                    endline += 1
    334                T = endline - start_read
    335                if rep == 0:
    336                    deltas = []
    337                    for t in range(T):
    338                        deltas.append([])
    339                for t in range(T):
    340                    deltas[t].append(np.zeros(len(data_starts)))
    341                # all other chunks should follow the same structure
    342                for cnfg in range(len(data_starts)):
    343                    start = data_starts[cnfg]
    344                    stop = start + data_starts[1]
    345                    chunk = content[start:stop]
    346                    try:
    347                        rep_idl.append(int(chunk[gauge_line].split(cfg_separator)[-1]))
    348                    except Exception:
    349                        raise Exception("Couldn't parse idl from directory, problem with chunk around line ", gauge_line)
    350
    351                    found_pat = ""
    352                    for li in chunk[corr_line + 1:corr_line + 6 + b2b]:
    353                        found_pat += li
    354                    if re.search(pattern, found_pat):
    355                        for t, line in enumerate(chunk[start_read:start_read + T]):
    356                            floats = list(map(float, line.split()))
    357                            deltas[t][rep][cnfg] = floats[im + 1 - single]
    358            idl.append(rep_idl)
    359
    360    if "check_configs" in kwargs:
    361        print("Checking for missing configs...")
    362        che = kwargs.get("check_configs")
    363        if not (len(che) == len(idl)):
    364            raise Exception("check_configs has to be the same length as replica!")
    365        for r in range(len(idl)):
    366            print("checking " + new_names[r])
    367            utils.check_idl(idl[r], che[r])
    368        print("Done")
    369    result = []
    370    for t in range(T):
    371        result.append(Obs(deltas[t], new_names, idl=idl))
    372    return result

Read sfcf c format 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.