pyerrors.input.hadrons

  1import os
  2from collections import Counter
  3from pathlib import Path
  4
  5import h5py
  6import numpy as np
  7
  8from ..correlators import Corr
  9from ..dirac import epsilon_tensor_rank4
 10from ..obs import CObs, Obs
 11from .misc import fit_t0
 12
 13
 14def _get_files(path, filestem, idl):
 15    ls = os.listdir(path)
 16
 17    # Clean up file list
 18    files = list(filter(lambda x: x.startswith(filestem + "."), ls))
 19
 20    if not files:
 21        raise FileNotFoundError(f'No files starting with {filestem} in folder {path}')
 22
 23    def get_cnfg_number(n):
 24        return int(n.replace(".h5", "")[len(filestem) + 1:])  # From python 3.9 onward the safer 'removesuffix' method can be used.
 25
 26    # Sort according to configuration number
 27    files.sort(key=get_cnfg_number)
 28
 29    cnfg_numbers = []
 30    filtered_files = []
 31    for line in files:
 32        no = get_cnfg_number(line)
 33        if idl:
 34            if no in list(idl):
 35                filtered_files.append(line)
 36                cnfg_numbers.append(no)
 37        else:
 38            filtered_files.append(line)
 39            cnfg_numbers.append(no)
 40
 41    if idl:
 42        if Counter(list(idl)) != Counter(cnfg_numbers):
 43            raise Exception("Not all configurations specified in idl found, configurations " + str(list(Counter(list(idl)) - Counter(cnfg_numbers))) + " are missing.")
 44
 45    # Check that configurations are evenly spaced
 46    dc = np.unique(np.diff(cnfg_numbers))
 47    if np.any(dc < 0):
 48        raise Exception("Unsorted files")
 49    if len(dc) == 1:
 50        idx = range(cnfg_numbers[0], cnfg_numbers[-1] + dc[0], dc[0])
 51    elif idl:
 52        idx = idl
 53    else:
 54        raise Exception("Configurations are not evenly spaced. Provide an idl if you want to proceed with this set of configurations.")
 55
 56    return filtered_files, idx
 57
 58
 59def read_hd5(filestem, ens_id, group, attrs=None, idl=None, part="real"):
 60    r'''Read hadrons hdf5 file and extract entry based on attributes.
 61
 62    Parameters
 63    -----------------
 64    filestem : str
 65        Full namestem of the files to read, including the full path.
 66    ens_id : str
 67        name of the ensemble, required for internal bookkeeping
 68    group : str
 69        label of the group to be extracted.
 70    attrs : dict or int
 71        Dictionary containing the attributes. For example
 72        ```python
 73        attrs = {"gamma_snk": "Gamma5",
 74                 "gamma_src": "Gamma5"}
 75         ```
 76        Alternatively an integer can be specified to identify the sub group.
 77        This is discouraged as the order in the file is not guaranteed.
 78    idl : range
 79        If specified only configurations in the given range are read in.
 80    part: str
 81        string specifying whether to extract the real part ('real'),
 82        the imaginary part ('imag') or a complex correlator ('complex').
 83        Default 'real'.
 84
 85    Returns
 86    -------
 87    corr : Corr
 88        Correlator of the source sink combination in question.
 89    '''
 90
 91    path_obj = Path(filestem)
 92    path = path_obj.parent.as_posix()
 93    filestem = path_obj.name
 94
 95    files, idx = _get_files(path, filestem, idl)
 96
 97    if isinstance(attrs, dict):
 98        h5file = h5py.File(path + '/' + files[0], "r")
 99        entry = None
100        for key in h5file[group].keys():
101            if attrs.items() <= {k: v[0].decode() for k, v in h5file[group][key].attrs.items()}.items():
102                if entry is None:
103                    entry = key
104                else:
105                    raise ValueError("More than one fitting entry found. More constraint on attributes needed.")
106        h5file.close()
107        if entry is None:
108            raise ValueError(f"Entry with attributes {attrs} not found.")
109    elif isinstance(attrs, int):
110        entry = group + f"_{attrs}"
111    else:
112        raise TypeError("Invalid type for 'attrs'. Needs to be dict or int.")
113
114    corr_data = []
115    infos = []
116    for hd5_file in files:
117        h5file = h5py.File(path + '/' + hd5_file, "r")
118        if group + '/' + entry not in h5file:
119            raise Exception("Entry '" + entry + "' not contained in the files.")
120        raw_data = h5file[group + '/' + entry + '/corr']
121        real_data = raw_data[:].view("complex")
122        corr_data.append(real_data)
123        if not infos:
124            for k, i in h5file[group + '/' + entry].attrs.items():
125                infos.append(k + ': ' + i[0].decode())
126        h5file.close()
127    corr_data = np.array(corr_data)
128
129    if part == "complex":
130        l_obs = []
131        for c in corr_data.T:
132            l_obs.append(CObs(Obs([c.real], [ens_id], idl=[idx]),
133                              Obs([c.imag], [ens_id], idl=[idx])))
134    else:
135        corr_data = getattr(corr_data, part)
136        l_obs = []
137        for c in corr_data.T:
138            l_obs.append(Obs([c], [ens_id], idl=[idx]))
139
140    corr = Corr(l_obs)
141    corr.tag = r", ".join(infos)
142    return corr
143
144
145def read_meson_hd5(path, filestem, ens_id, meson='meson_0', idl=None, gammas=None):
146    r'''Read hadrons meson hdf5 file and extract the meson labeled 'meson'
147
148    Parameters
149    -----------------
150    path : str
151        path to the files to read
152    filestem : str
153        namestem of the files to read
154    ens_id : str
155        name of the ensemble, required for internal bookkeeping
156    meson : str
157        label of the meson to be extracted, standard value meson_0 which
158        corresponds to the pseudoscalar pseudoscalar two-point function.
159    gammas : tuple of strings
160        Instrad of a meson label one can also provide a tuple of two strings
161        indicating the gamma matrices at sink and source (gamma_snk, gamma_src).
162        ("Gamma5", "Gamma5") corresponds to the pseudoscalar pseudoscalar
163        two-point function. The gammas argument dominateds over meson.
164    idl : range
165        If specified only configurations in the given range are read in.
166
167    Returns
168    -------
169    corr : Corr
170        Correlator of the source sink combination in question.
171    '''
172    if gammas is None:
173        attrs = int(meson.rsplit('_', 1)[-1])
174    else:
175        if len(gammas) != 2:
176            raise ValueError("'gammas' needs to have exactly two entries")
177        attrs = {"gamma_snk": gammas[0],
178                 "gamma_src": gammas[1]}
179    return read_hd5(filestem=path + "/" + filestem, ens_id=ens_id,
180                    group=meson.rsplit('_', 1)[0], attrs=attrs, idl=idl,
181                    part="real")
182
183
184def _extract_real_arrays(path, files, tree, keys):
185    corr_data = {}
186    for key in keys:
187        corr_data[key] = []
188    for hd5_file in files:
189        h5file = h5py.File(path + '/' + hd5_file, "r")
190        for key in keys:
191            if tree + '/' + key not in h5file:
192                raise Exception("Entry '" + key + "' not contained in the files.")
193            raw_data = h5file[tree + '/' + key + '/data']
194            real_data = raw_data[:].astype(np.double)
195            corr_data[key].append(real_data)
196        h5file.close()
197    for key in keys:
198        corr_data[key] = np.array(corr_data[key])
199    return corr_data
200
201
202def extract_t0_hd5(path, filestem, ens_id, obs='Clover energy density', fit_range=5, idl=None, **kwargs):
203    r'''Read hadrons FlowObservables hdf5 file and extract t0
204
205    Parameters
206    -----------------
207    path : str
208        path to the files to read
209    filestem : str
210        namestem of the files to read
211    ens_id : str
212        name of the ensemble, required for internal bookkeeping
213    obs : str
214        label of the observable from which t0 should be extracted.
215        Options: 'Clover energy density' and 'Plaquette energy density'
216    fit_range : int
217        Number of data points left and right of the zero
218        crossing to be included in the linear fit. (Default: 5)
219    idl : range
220        If specified only configurations in the given range are read in.
221    plot_fit : bool
222        If true, the fit for the extraction of t0 is shown together with the data.
223    '''
224
225    files, idx = _get_files(path, filestem, idl)
226    tree = "FlowObservables"
227
228    h5file = h5py.File(path + '/' + files[0], "r")
229    obs_key = None
230    for key in h5file[tree].keys():
231        if obs == h5file[tree][key].attrs["description"][0].decode():
232            obs_key = key
233            break
234    h5file.close()
235    if obs_key is None:
236        raise Exception(f"Observable {obs} not found.")
237
238    corr_data = _extract_real_arrays(path, files, tree, ["FlowObservables_0", obs_key])
239
240    if not np.allclose(corr_data["FlowObservables_0"][0], corr_data["FlowObservables_0"][:]):
241        raise Exception("Not all flow times were equal.")
242
243    t2E_dict = {}
244    for t2, dat in zip(corr_data["FlowObservables_0"][0], corr_data[obs_key].T, strict=True):
245        t2E_dict[t2] = Obs([dat], [ens_id], idl=[idx]) - 0.3
246
247    return fit_t0(t2E_dict, fit_range, plot_fit=kwargs.get('plot_fit'))
248
249
250def read_DistillationContraction_hd5(path, ens_id, diagrams=None, idl=None):
251    """Read hadrons DistillationContraction hdf5 files in given directory structure
252
253    Parameters
254    -----------------
255    path : str
256        path to the directories to read
257    ens_id : str
258        name of the ensemble, required for internal bookkeeping
259    diagrams : list
260        List of strings of the diagrams to extract, e.g. ["direct", "box", "cross"].
261    idl : range
262        If specified only configurations in the given range are read in.
263
264    Returns
265    -------
266    result : dict
267        extracted DistillationContration data
268    """
269
270    if diagrams is None:
271        diagrams = ["direct"]
272
273    res_dict = {}
274
275    directories, idx = _get_files(path, "data", idl)
276
277    explore_path = Path(path + "/" + directories[0])
278
279    for explore_file in explore_path.iterdir():
280        if explore_file.is_file():
281            stem = explore_file.with_suffix("").with_suffix("").as_posix().split("/")[-1]
282        else:
283            continue
284
285        file_list = []
286        for dir in directories:
287            tmp_path = Path(path + "/" + dir)
288            file_list.append((tmp_path / stem).as_posix() + tmp_path.suffix + ".h5")
289
290        corr_data = {}
291
292        for diagram in diagrams:
293            corr_data[diagram] = []
294
295        try:
296            for n_file, (hd5_file, _n_traj) in enumerate(zip(file_list, list(idx), strict=True)):
297                h5file = h5py.File(hd5_file)
298
299                if n_file == 0:
300                    if h5file["DistillationContraction/Metadata"].attrs.get("TimeSources")[0].decode() != "0...":
301                        raise NotImplementedError("Routine is only implemented for files containing inversions on all timeslices.")
302
303                    Nt = h5file["DistillationContraction/Metadata"].attrs.get("Nt")[0]
304
305                    identifier = []
306                    for in_file in range(len(h5file["DistillationContraction/Metadata/DmfInputFiles"].attrs.keys()) - 1):
307                        encoded_info = h5file["DistillationContraction/Metadata/DmfInputFiles"].attrs.get("DmfInputFiles_" + str(in_file))
308                        full_info = encoded_info[0].decode().split("/")[-1].replace(".h5", "").split("_")
309                        my_tuple = (full_info[0], full_info[1][1:], full_info[2], full_info[3])
310                        identifier.append(my_tuple)
311                    identifier = tuple(identifier)
312                    # "DistillationContraction/Metadata/DmfSuffix" contains info about different quarks, irrelevant in the SU(3) case.
313
314                for diagram in diagrams:
315
316                    if diagram == "triangle" and "Identity" not in str(identifier):
317                        part = "im"
318                    else:
319                        part = "re"
320
321                    real_data = np.zeros(Nt)
322                    for x0 in range(Nt):
323                        raw_data = h5file["DistillationContraction/Correlators/" + diagram + "/" + str(x0)][:][part].astype(np.double)
324                        real_data += np.roll(raw_data, -x0)
325                    real_data /= Nt
326
327                    corr_data[diagram].append(real_data)
328                h5file.close()
329
330            res_dict[str(identifier)] = {}
331
332            for diagram in diagrams:
333
334                tmp_data = np.array(corr_data[diagram])
335
336                l_obs = []
337                for c in tmp_data.T:
338                    l_obs.append(Obs([c], [ens_id], idl=[idx]))
339
340                corr = Corr(l_obs)
341                corr.tag = str(identifier)
342
343                res_dict[str(identifier)][diagram] = corr
344        except FileNotFoundError:
345            print("Skip", stem)
346
347    return res_dict
348
349
350class Npr_matrix(np.ndarray):
351
352    def __new__(cls, input_array, mom_in=None, mom_out=None):
353        obj = np.asarray(input_array).view(cls)
354        obj.mom_in = mom_in
355        obj.mom_out = mom_out
356        return obj
357
358    @property
359    def g5H(self):
360        """Gamma_5 hermitean conjugate
361
362        Uses the fact that the propagator is gamma5 hermitean, so just the
363        in and out momenta of the propagator are exchanged.
364        """
365        return Npr_matrix(self,
366                          mom_in=self.mom_out,
367                          mom_out=self.mom_in)
368
369    def _propagate_mom(self, other, name):
370        s_mom = getattr(self, name, None)
371        o_mom = getattr(other, name, None)
372        if s_mom is not None and o_mom is not None:
373            if not np.allclose(s_mom, o_mom):
374                raise Exception(name + ' does not match.')
375        return o_mom if o_mom is not None else s_mom
376
377    def __matmul__(self, other):
378        return self.__new__(Npr_matrix,
379                            super().__matmul__(other),
380                            self._propagate_mom(other, 'mom_in'),
381                            self._propagate_mom(other, 'mom_out'))
382
383    def __array_finalize__(self, obj):
384        if obj is None:
385            return
386        self.mom_in = getattr(obj, 'mom_in', None)
387        self.mom_out = getattr(obj, 'mom_out', None)
388
389
390def read_ExternalLeg_hd5(path, filestem, ens_id, idl=None):
391    """Read hadrons ExternalLeg hdf5 file and output an array of CObs
392
393    Parameters
394    ----------
395    path : str
396        path to the files to read
397    filestem : str
398        namestem of the files to read
399    ens_id : str
400        name of the ensemble, required for internal bookkeeping
401    idl : range
402        If specified only configurations in the given range are read in.
403
404    Returns
405    -------
406    result : Npr_matrix
407        read Cobs-matrix
408    """
409
410    files, idx = _get_files(path, filestem, idl)
411
412    mom = None
413
414    corr_data = []
415    for hd5_file in files:
416        file = h5py.File(path + '/' + hd5_file, "r")
417        raw_data = file['ExternalLeg/corr'][0][0].view('complex')
418        corr_data.append(raw_data)
419        if mom is None:
420            mom = np.array(str(file['ExternalLeg/info'].attrs['pIn'])[3:-2].strip().split(), dtype=float)
421        file.close()
422    corr_data = np.array(corr_data)
423
424    rolled_array = np.rollaxis(corr_data, 0, 5)
425
426    matrix = np.empty((rolled_array.shape[:-1]), dtype=object)
427    for si, sj, ci, cj in np.ndindex(rolled_array.shape[:-1]):
428        real = Obs([rolled_array[si, sj, ci, cj].real], [ens_id], idl=[idx])
429        imag = Obs([rolled_array[si, sj, ci, cj].imag], [ens_id], idl=[idx])
430        matrix[si, sj, ci, cj] = CObs(real, imag)
431
432    return Npr_matrix(matrix, mom_in=mom)
433
434
435def read_Bilinear_hd5(path, filestem, ens_id, idl=None):
436    """Read hadrons Bilinear hdf5 file and output an array of CObs
437
438    Parameters
439    ----------
440    path : str
441        path to the files to read
442    filestem : str
443        namestem of the files to read
444    ens_id : str
445        name of the ensemble, required for internal bookkeeping
446    idl : range
447        If specified only configurations in the given range are read in.
448
449    Returns
450    -------
451    result_dict: dict[Npr_matrix]
452        extracted Bilinears
453    """
454
455    files, idx = _get_files(path, filestem, idl)
456
457    mom_in = None
458    mom_out = None
459
460    corr_data = {}
461    for hd5_file in files:
462        file = h5py.File(path + '/' + hd5_file, "r")
463        for i in range(16):
464            name = file['Bilinear/Bilinear_' + str(i) + '/info'].attrs['gamma'][0].decode('UTF-8')
465            if name not in corr_data:
466                corr_data[name] = []
467            raw_data = file['Bilinear/Bilinear_' + str(i) + '/corr'][0][0].view('complex')
468            corr_data[name].append(raw_data)
469            if mom_in is None:
470                mom_in = np.array(str(file['Bilinear/Bilinear_' + str(i) + '/info'].attrs['pIn'])[3:-2].strip().split(), dtype=float)
471            if mom_out is None:
472                mom_out = np.array(str(file['Bilinear/Bilinear_' + str(i) + '/info'].attrs['pOut'])[3:-2].strip().split(), dtype=float)
473
474        file.close()
475
476    result_dict = {}
477
478    for key, data in corr_data.items():
479        local_data = np.array(data)
480
481        rolled_array = np.rollaxis(local_data, 0, 5)
482
483        matrix = np.empty((rolled_array.shape[:-1]), dtype=object)
484        for si, sj, ci, cj in np.ndindex(rolled_array.shape[:-1]):
485            real = Obs([rolled_array[si, sj, ci, cj].real], [ens_id], idl=[idx])
486            imag = Obs([rolled_array[si, sj, ci, cj].imag], [ens_id], idl=[idx])
487            matrix[si, sj, ci, cj] = CObs(real, imag)
488
489        result_dict[key] = Npr_matrix(matrix, mom_in=mom_in, mom_out=mom_out)
490
491    return result_dict
492
493
494def read_Fourquark_hd5(path, filestem, ens_id, idl=None, vertices=None):
495    """Read hadrons FourquarkFullyConnected hdf5 file and output an array of CObs
496
497    Parameters
498    ----------
499    path : str
500        path to the files to read
501    filestem : str
502        namestem of the files to read
503    ens_id : str
504        name of the ensemble, required for internal bookkeeping
505    idl : range
506        If specified only configurations in the given range are read in.
507    vertices : list
508        Vertex functions to be extracted.
509
510    Returns
511    -------
512    result_dict : dict
513        extracted fourquark matrizes
514    """
515
516    if vertices is None:
517        vertices = ["VA", "AV"]
518
519    files, idx = _get_files(path, filestem, idl)
520
521    mom_in = None
522    mom_out = None
523
524    vertex_names = []
525    for vertex in vertices:
526        vertex_names += _get_lorentz_names(vertex)
527
528    corr_data = {}
529
530    tree = 'FourQuarkFullyConnected/FourQuarkFullyConnected_'
531
532    for hd5_file in files:
533        file = h5py.File(path + '/' + hd5_file, "r")
534
535        for i in range(32):
536            name = (file[tree + str(i) + '/info'].attrs['gammaA'][0].decode('UTF-8'), file[tree + str(i) + '/info'].attrs['gammaB'][0].decode('UTF-8'))
537            if name in vertex_names:
538                if name not in corr_data:
539                    corr_data[name] = []
540                raw_data = file[tree + str(i) + '/corr'][0][0].view('complex')
541                corr_data[name].append(raw_data)
542                if mom_in is None:
543                    mom_in = np.array(str(file[tree + str(i) + '/info'].attrs['pIn'])[3:-2].strip().split(), dtype=float)
544                if mom_out is None:
545                    mom_out = np.array(str(file[tree + str(i) + '/info'].attrs['pOut'])[3:-2].strip().split(), dtype=float)
546
547        file.close()
548
549    intermediate_dict = {}
550
551    for vertex in vertices:
552        lorentz_names = _get_lorentz_names(vertex)
553        for v_name in lorentz_names:
554            if v_name in [('SigmaXY', 'SigmaZT'),
555                          ('SigmaXT', 'SigmaYZ'),
556                          ('SigmaYZ', 'SigmaXT'),
557                          ('SigmaZT', 'SigmaXY')]:
558                sign = -1
559            else:
560                sign = 1
561            if vertex not in intermediate_dict:
562                intermediate_dict[vertex] = sign * np.array(corr_data[v_name])
563            else:
564                intermediate_dict[vertex] += sign * np.array(corr_data[v_name])
565
566    result_dict = {}
567
568    for key, data in intermediate_dict.items():
569
570        rolled_array = np.moveaxis(data, 0, 8)
571
572        matrix = np.empty((rolled_array.shape[:-1]), dtype=object)
573        for index in np.ndindex(rolled_array.shape[:-1]):
574            real = Obs([rolled_array[index].real], [ens_id], idl=[idx])
575            imag = Obs([rolled_array[index].imag], [ens_id], idl=[idx])
576            matrix[index] = CObs(real, imag)
577
578        result_dict[key] = Npr_matrix(matrix, mom_in=mom_in, mom_out=mom_out)
579
580    return result_dict
581
582
583def _get_lorentz_names(name):
584    lorentz_index = ['X', 'Y', 'Z', 'T']
585
586    res = []
587
588    if name == "TT":
589        for i in range(4):
590            for j in range(i + 1, 4):
591                res.append(("Sigma" + lorentz_index[i] + lorentz_index[j], "Sigma" + lorentz_index[i] + lorentz_index[j]))
592        return res
593
594    if name == "TTtilde":
595        for i in range(4):
596            for j in range(i + 1, 4):
597                for k in range(4):
598                    for o in range(k + 1, 4):
599                        fac = epsilon_tensor_rank4(i, j, k, o)
600                        if not np.isclose(fac, 0.0):
601                            res.append(("Sigma" + lorentz_index[i] + lorentz_index[j], "Sigma" + lorentz_index[k] + lorentz_index[o]))
602        return res
603
604    assert len(name) == 2
605
606    if 'S' in name or 'P' in name:
607        if not set(name) <= set(['S', 'P']):
608            raise Exception("'" + name + "' is not a Lorentz scalar")
609
610        g_names = {'S': 'Identity',
611                   'P': 'Gamma5'}
612
613        res.append((g_names[name[0]], g_names[name[1]]))
614
615    else:
616        if not set(name) <= set(['V', 'A']):
617            raise Exception("'" + name + "' is not a Lorentz scalar")
618
619        for ind in lorentz_index:
620            res.append(('Gamma' + ind + (name[0] == 'A') * 'Gamma5',
621                        'Gamma' + ind + (name[1] == 'A') * 'Gamma5'))
622
623    return res
def read_hd5(filestem, ens_id, group, attrs=None, idl=None, part='real'):
 60def read_hd5(filestem, ens_id, group, attrs=None, idl=None, part="real"):
 61    r'''Read hadrons hdf5 file and extract entry based on attributes.
 62
 63    Parameters
 64    -----------------
 65    filestem : str
 66        Full namestem of the files to read, including the full path.
 67    ens_id : str
 68        name of the ensemble, required for internal bookkeeping
 69    group : str
 70        label of the group to be extracted.
 71    attrs : dict or int
 72        Dictionary containing the attributes. For example
 73        ```python
 74        attrs = {"gamma_snk": "Gamma5",
 75                 "gamma_src": "Gamma5"}
 76         ```
 77        Alternatively an integer can be specified to identify the sub group.
 78        This is discouraged as the order in the file is not guaranteed.
 79    idl : range
 80        If specified only configurations in the given range are read in.
 81    part: str
 82        string specifying whether to extract the real part ('real'),
 83        the imaginary part ('imag') or a complex correlator ('complex').
 84        Default 'real'.
 85
 86    Returns
 87    -------
 88    corr : Corr
 89        Correlator of the source sink combination in question.
 90    '''
 91
 92    path_obj = Path(filestem)
 93    path = path_obj.parent.as_posix()
 94    filestem = path_obj.name
 95
 96    files, idx = _get_files(path, filestem, idl)
 97
 98    if isinstance(attrs, dict):
 99        h5file = h5py.File(path + '/' + files[0], "r")
100        entry = None
101        for key in h5file[group].keys():
102            if attrs.items() <= {k: v[0].decode() for k, v in h5file[group][key].attrs.items()}.items():
103                if entry is None:
104                    entry = key
105                else:
106                    raise ValueError("More than one fitting entry found. More constraint on attributes needed.")
107        h5file.close()
108        if entry is None:
109            raise ValueError(f"Entry with attributes {attrs} not found.")
110    elif isinstance(attrs, int):
111        entry = group + f"_{attrs}"
112    else:
113        raise TypeError("Invalid type for 'attrs'. Needs to be dict or int.")
114
115    corr_data = []
116    infos = []
117    for hd5_file in files:
118        h5file = h5py.File(path + '/' + hd5_file, "r")
119        if group + '/' + entry not in h5file:
120            raise Exception("Entry '" + entry + "' not contained in the files.")
121        raw_data = h5file[group + '/' + entry + '/corr']
122        real_data = raw_data[:].view("complex")
123        corr_data.append(real_data)
124        if not infos:
125            for k, i in h5file[group + '/' + entry].attrs.items():
126                infos.append(k + ': ' + i[0].decode())
127        h5file.close()
128    corr_data = np.array(corr_data)
129
130    if part == "complex":
131        l_obs = []
132        for c in corr_data.T:
133            l_obs.append(CObs(Obs([c.real], [ens_id], idl=[idx]),
134                              Obs([c.imag], [ens_id], idl=[idx])))
135    else:
136        corr_data = getattr(corr_data, part)
137        l_obs = []
138        for c in corr_data.T:
139            l_obs.append(Obs([c], [ens_id], idl=[idx]))
140
141    corr = Corr(l_obs)
142    corr.tag = r", ".join(infos)
143    return corr

Read hadrons hdf5 file and extract entry based on attributes.

Parameters
  • filestem (str): Full namestem of the files to read, including the full path.
  • ens_id (str): name of the ensemble, required for internal bookkeeping
  • group (str): label of the group to be extracted.
  • attrs (dict or int): Dictionary containing the attributes. For example

    attrs = {"gamma_snk": "Gamma5",
             "gamma_src": "Gamma5"}
    

    Alternatively an integer can be specified to identify the sub group. This is discouraged as the order in the file is not guaranteed.

  • idl (range): If specified only configurations in the given range are read in.
  • part (str): string specifying whether to extract the real part ('real'), the imaginary part ('imag') or a complex correlator ('complex'). Default 'real'.
Returns
  • corr (Corr): Correlator of the source sink combination in question.
def read_meson_hd5(path, filestem, ens_id, meson='meson_0', idl=None, gammas=None):
146def read_meson_hd5(path, filestem, ens_id, meson='meson_0', idl=None, gammas=None):
147    r'''Read hadrons meson hdf5 file and extract the meson labeled 'meson'
148
149    Parameters
150    -----------------
151    path : str
152        path to the files to read
153    filestem : str
154        namestem of the files to read
155    ens_id : str
156        name of the ensemble, required for internal bookkeeping
157    meson : str
158        label of the meson to be extracted, standard value meson_0 which
159        corresponds to the pseudoscalar pseudoscalar two-point function.
160    gammas : tuple of strings
161        Instrad of a meson label one can also provide a tuple of two strings
162        indicating the gamma matrices at sink and source (gamma_snk, gamma_src).
163        ("Gamma5", "Gamma5") corresponds to the pseudoscalar pseudoscalar
164        two-point function. The gammas argument dominateds over meson.
165    idl : range
166        If specified only configurations in the given range are read in.
167
168    Returns
169    -------
170    corr : Corr
171        Correlator of the source sink combination in question.
172    '''
173    if gammas is None:
174        attrs = int(meson.rsplit('_', 1)[-1])
175    else:
176        if len(gammas) != 2:
177            raise ValueError("'gammas' needs to have exactly two entries")
178        attrs = {"gamma_snk": gammas[0],
179                 "gamma_src": gammas[1]}
180    return read_hd5(filestem=path + "/" + filestem, ens_id=ens_id,
181                    group=meson.rsplit('_', 1)[0], attrs=attrs, idl=idl,
182                    part="real")

Read hadrons meson hdf5 file and extract the meson labeled 'meson'

Parameters
  • path (str): path to the files to read
  • filestem (str): namestem of the files to read
  • ens_id (str): name of the ensemble, required for internal bookkeeping
  • meson (str): label of the meson to be extracted, standard value meson_0 which corresponds to the pseudoscalar pseudoscalar two-point function.
  • gammas (tuple of strings): Instrad of a meson label one can also provide a tuple of two strings indicating the gamma matrices at sink and source (gamma_snk, gamma_src). ("Gamma5", "Gamma5") corresponds to the pseudoscalar pseudoscalar two-point function. The gammas argument dominateds over meson.
  • idl (range): If specified only configurations in the given range are read in.
Returns
  • corr (Corr): Correlator of the source sink combination in question.
def extract_t0_hd5( path, filestem, ens_id, obs='Clover energy density', fit_range=5, idl=None, **kwargs):
203def extract_t0_hd5(path, filestem, ens_id, obs='Clover energy density', fit_range=5, idl=None, **kwargs):
204    r'''Read hadrons FlowObservables hdf5 file and extract t0
205
206    Parameters
207    -----------------
208    path : str
209        path to the files to read
210    filestem : str
211        namestem of the files to read
212    ens_id : str
213        name of the ensemble, required for internal bookkeeping
214    obs : str
215        label of the observable from which t0 should be extracted.
216        Options: 'Clover energy density' and 'Plaquette energy density'
217    fit_range : int
218        Number of data points left and right of the zero
219        crossing to be included in the linear fit. (Default: 5)
220    idl : range
221        If specified only configurations in the given range are read in.
222    plot_fit : bool
223        If true, the fit for the extraction of t0 is shown together with the data.
224    '''
225
226    files, idx = _get_files(path, filestem, idl)
227    tree = "FlowObservables"
228
229    h5file = h5py.File(path + '/' + files[0], "r")
230    obs_key = None
231    for key in h5file[tree].keys():
232        if obs == h5file[tree][key].attrs["description"][0].decode():
233            obs_key = key
234            break
235    h5file.close()
236    if obs_key is None:
237        raise Exception(f"Observable {obs} not found.")
238
239    corr_data = _extract_real_arrays(path, files, tree, ["FlowObservables_0", obs_key])
240
241    if not np.allclose(corr_data["FlowObservables_0"][0], corr_data["FlowObservables_0"][:]):
242        raise Exception("Not all flow times were equal.")
243
244    t2E_dict = {}
245    for t2, dat in zip(corr_data["FlowObservables_0"][0], corr_data[obs_key].T, strict=True):
246        t2E_dict[t2] = Obs([dat], [ens_id], idl=[idx]) - 0.3
247
248    return fit_t0(t2E_dict, fit_range, plot_fit=kwargs.get('plot_fit'))

Read hadrons FlowObservables hdf5 file and extract t0

Parameters
  • path (str): path to the files to read
  • filestem (str): namestem of the files to read
  • ens_id (str): name of the ensemble, required for internal bookkeeping
  • obs (str): label of the observable from which t0 should be extracted. Options: 'Clover energy density' and 'Plaquette energy density'
  • fit_range (int): Number of data points left and right of the zero crossing to be included in the linear fit. (Default: 5)
  • idl (range): If specified only configurations in the given range are read in.
  • plot_fit (bool): If true, the fit for the extraction of t0 is shown together with the data.
def read_DistillationContraction_hd5(path, ens_id, diagrams=None, idl=None):
251def read_DistillationContraction_hd5(path, ens_id, diagrams=None, idl=None):
252    """Read hadrons DistillationContraction hdf5 files in given directory structure
253
254    Parameters
255    -----------------
256    path : str
257        path to the directories to read
258    ens_id : str
259        name of the ensemble, required for internal bookkeeping
260    diagrams : list
261        List of strings of the diagrams to extract, e.g. ["direct", "box", "cross"].
262    idl : range
263        If specified only configurations in the given range are read in.
264
265    Returns
266    -------
267    result : dict
268        extracted DistillationContration data
269    """
270
271    if diagrams is None:
272        diagrams = ["direct"]
273
274    res_dict = {}
275
276    directories, idx = _get_files(path, "data", idl)
277
278    explore_path = Path(path + "/" + directories[0])
279
280    for explore_file in explore_path.iterdir():
281        if explore_file.is_file():
282            stem = explore_file.with_suffix("").with_suffix("").as_posix().split("/")[-1]
283        else:
284            continue
285
286        file_list = []
287        for dir in directories:
288            tmp_path = Path(path + "/" + dir)
289            file_list.append((tmp_path / stem).as_posix() + tmp_path.suffix + ".h5")
290
291        corr_data = {}
292
293        for diagram in diagrams:
294            corr_data[diagram] = []
295
296        try:
297            for n_file, (hd5_file, _n_traj) in enumerate(zip(file_list, list(idx), strict=True)):
298                h5file = h5py.File(hd5_file)
299
300                if n_file == 0:
301                    if h5file["DistillationContraction/Metadata"].attrs.get("TimeSources")[0].decode() != "0...":
302                        raise NotImplementedError("Routine is only implemented for files containing inversions on all timeslices.")
303
304                    Nt = h5file["DistillationContraction/Metadata"].attrs.get("Nt")[0]
305
306                    identifier = []
307                    for in_file in range(len(h5file["DistillationContraction/Metadata/DmfInputFiles"].attrs.keys()) - 1):
308                        encoded_info = h5file["DistillationContraction/Metadata/DmfInputFiles"].attrs.get("DmfInputFiles_" + str(in_file))
309                        full_info = encoded_info[0].decode().split("/")[-1].replace(".h5", "").split("_")
310                        my_tuple = (full_info[0], full_info[1][1:], full_info[2], full_info[3])
311                        identifier.append(my_tuple)
312                    identifier = tuple(identifier)
313                    # "DistillationContraction/Metadata/DmfSuffix" contains info about different quarks, irrelevant in the SU(3) case.
314
315                for diagram in diagrams:
316
317                    if diagram == "triangle" and "Identity" not in str(identifier):
318                        part = "im"
319                    else:
320                        part = "re"
321
322                    real_data = np.zeros(Nt)
323                    for x0 in range(Nt):
324                        raw_data = h5file["DistillationContraction/Correlators/" + diagram + "/" + str(x0)][:][part].astype(np.double)
325                        real_data += np.roll(raw_data, -x0)
326                    real_data /= Nt
327
328                    corr_data[diagram].append(real_data)
329                h5file.close()
330
331            res_dict[str(identifier)] = {}
332
333            for diagram in diagrams:
334
335                tmp_data = np.array(corr_data[diagram])
336
337                l_obs = []
338                for c in tmp_data.T:
339                    l_obs.append(Obs([c], [ens_id], idl=[idx]))
340
341                corr = Corr(l_obs)
342                corr.tag = str(identifier)
343
344                res_dict[str(identifier)][diagram] = corr
345        except FileNotFoundError:
346            print("Skip", stem)
347
348    return res_dict

Read hadrons DistillationContraction hdf5 files in given directory structure

Parameters
  • path (str): path to the directories to read
  • ens_id (str): name of the ensemble, required for internal bookkeeping
  • diagrams (list): List of strings of the diagrams to extract, e.g. ["direct", "box", "cross"].
  • idl (range): If specified only configurations in the given range are read in.
Returns
  • result (dict): extracted DistillationContration data
class Npr_matrix(numpy.ndarray):
351class Npr_matrix(np.ndarray):
352
353    def __new__(cls, input_array, mom_in=None, mom_out=None):
354        obj = np.asarray(input_array).view(cls)
355        obj.mom_in = mom_in
356        obj.mom_out = mom_out
357        return obj
358
359    @property
360    def g5H(self):
361        """Gamma_5 hermitean conjugate
362
363        Uses the fact that the propagator is gamma5 hermitean, so just the
364        in and out momenta of the propagator are exchanged.
365        """
366        return Npr_matrix(self,
367                          mom_in=self.mom_out,
368                          mom_out=self.mom_in)
369
370    def _propagate_mom(self, other, name):
371        s_mom = getattr(self, name, None)
372        o_mom = getattr(other, name, None)
373        if s_mom is not None and o_mom is not None:
374            if not np.allclose(s_mom, o_mom):
375                raise Exception(name + ' does not match.')
376        return o_mom if o_mom is not None else s_mom
377
378    def __matmul__(self, other):
379        return self.__new__(Npr_matrix,
380                            super().__matmul__(other),
381                            self._propagate_mom(other, 'mom_in'),
382                            self._propagate_mom(other, 'mom_out'))
383
384    def __array_finalize__(self, obj):
385        if obj is None:
386            return
387        self.mom_in = getattr(obj, 'mom_in', None)
388        self.mom_out = getattr(obj, 'mom_out', None)

ndarray(shape, dtype=np.float64, buffer=None, offset=0, strides=None, order=None)

An array object represents a multidimensional, homogeneous array of fixed-size items. An associated data-type object describes the format of each element in the array (its byte-order, how many bytes it occupies in memory, whether it is an integer, a floating point number, or something else, etc.)

Arrays should be constructed using array, zeros or empty (refer to the See Also section below). The parameters given here refer to a low-level method (ndarray(...)) for instantiating an array.

For more information, refer to the numpy module and examine the methods and attributes of an array.

Parameters
  • (for the __new__ method; see Notes below)
  • shape (tuple of ints): Shape of created array.
  • dtype (data-type, optional): Any object that can be interpreted as a numpy data type. Default is numpy.float64.
  • buffer (object exposing buffer interface, optional): Used to fill the array with data.
  • offset (int, optional): Offset of array data in buffer.
  • strides (tuple of ints, optional): Strides of data in memory.
  • order ({'C', 'F'}, optional): Row-major (C-style) or column-major (Fortran-style) order.
Attributes
  • T (ndarray): Transpose of the array.
  • data (buffer): The array's elements, in memory.
  • dtype (dtype object): Describes the format of the elements in the array.
  • flags (dict): Dictionary containing information related to memory use, e.g., 'C_CONTIGUOUS', 'OWNDATA', 'WRITEABLE', etc.
  • flat (numpy.flatiter object): Flattened version of the array as an iterator. The iterator allows assignments, e.g., x.flat = 3 (See ndarray.flat for assignment examples; TODO).
  • imag (ndarray): Imaginary part of the array.
  • real (ndarray): Real part of the array.
  • size (int): Number of elements in the array.
  • itemsize (int): The memory use of each array element in bytes.
  • nbytes (int): The total number of bytes required to store the array data, i.e., itemsize * size.
  • ndim (int): The array's number of dimensions.
  • shape (tuple of ints): Shape of the array.
  • strides (tuple of ints): The step-size required to move from one element to the next in memory. For example, a contiguous (3, 4) array of type int16 in C-order has strides (8, 2). This implies that to move from element to element in memory requires jumps of 2 bytes. To move from row-to-row, one needs to jump 8 bytes at a time (2 * 4).
  • ctypes (ctypes object): Class containing properties of the array needed for interaction with ctypes.
  • base (ndarray): If the array is a view into another array, that array is its base (unless that array is also a view). The base array is where the array data is actually stored.
See Also

array: Construct an array.
zeros: Create an array, each element of which is zero.
empty: Create an array, but leave its allocated memory unchanged (i.e., it contains "garbage").
dtype: Create a data-type.
numpy.typing.NDArray: An ndarray alias :term:generic <generic type> w.r.t. its dtype.type <numpy.dtype.type>.

Notes

There are two modes of creating an array using __new__:

  1. If buffer is None, then only shape, dtype, and order are used.
  2. If buffer is an object exposing the buffer interface, then all keywords are interpreted.

No __init__ method is needed because the array is fully initialized after the __new__ method.

Examples

These examples illustrate the low-level ndarray constructor. Refer to the See Also section above for easier ways of constructing an ndarray.

First mode, buffer is None:

>>> import numpy as np
>>> np.ndarray(shape=(2,2), dtype=np.float64, order='F')
array([[0.0e+000, 0.0e+000], # random
       [     nan, 2.5e-323]])

Second mode:

>>> np.ndarray((2,), buffer=np.array([1,2,3]),
...            offset=np.int_().itemsize,
...            dtype=np.int_) # offset = 1*itemsize, i.e. skip first element
array([2, 3])
g5H
359    @property
360    def g5H(self):
361        """Gamma_5 hermitean conjugate
362
363        Uses the fact that the propagator is gamma5 hermitean, so just the
364        in and out momenta of the propagator are exchanged.
365        """
366        return Npr_matrix(self,
367                          mom_in=self.mom_out,
368                          mom_out=self.mom_in)

Gamma_5 hermitean conjugate

Uses the fact that the propagator is gamma5 hermitean, so just the in and out momenta of the propagator are exchanged.

def read_ExternalLeg_hd5(path, filestem, ens_id, idl=None):
391def read_ExternalLeg_hd5(path, filestem, ens_id, idl=None):
392    """Read hadrons ExternalLeg hdf5 file and output an array of CObs
393
394    Parameters
395    ----------
396    path : str
397        path to the files to read
398    filestem : str
399        namestem of the files to read
400    ens_id : str
401        name of the ensemble, required for internal bookkeeping
402    idl : range
403        If specified only configurations in the given range are read in.
404
405    Returns
406    -------
407    result : Npr_matrix
408        read Cobs-matrix
409    """
410
411    files, idx = _get_files(path, filestem, idl)
412
413    mom = None
414
415    corr_data = []
416    for hd5_file in files:
417        file = h5py.File(path + '/' + hd5_file, "r")
418        raw_data = file['ExternalLeg/corr'][0][0].view('complex')
419        corr_data.append(raw_data)
420        if mom is None:
421            mom = np.array(str(file['ExternalLeg/info'].attrs['pIn'])[3:-2].strip().split(), dtype=float)
422        file.close()
423    corr_data = np.array(corr_data)
424
425    rolled_array = np.rollaxis(corr_data, 0, 5)
426
427    matrix = np.empty((rolled_array.shape[:-1]), dtype=object)
428    for si, sj, ci, cj in np.ndindex(rolled_array.shape[:-1]):
429        real = Obs([rolled_array[si, sj, ci, cj].real], [ens_id], idl=[idx])
430        imag = Obs([rolled_array[si, sj, ci, cj].imag], [ens_id], idl=[idx])
431        matrix[si, sj, ci, cj] = CObs(real, imag)
432
433    return Npr_matrix(matrix, mom_in=mom)

Read hadrons ExternalLeg hdf5 file and output an array of CObs

Parameters
  • path (str): path to the files to read
  • filestem (str): namestem of the files to read
  • ens_id (str): name of the ensemble, required for internal bookkeeping
  • idl (range): If specified only configurations in the given range are read in.
Returns
  • result (Npr_matrix): read Cobs-matrix
def read_Bilinear_hd5(path, filestem, ens_id, idl=None):
436def read_Bilinear_hd5(path, filestem, ens_id, idl=None):
437    """Read hadrons Bilinear hdf5 file and output an array of CObs
438
439    Parameters
440    ----------
441    path : str
442        path to the files to read
443    filestem : str
444        namestem of the files to read
445    ens_id : str
446        name of the ensemble, required for internal bookkeeping
447    idl : range
448        If specified only configurations in the given range are read in.
449
450    Returns
451    -------
452    result_dict: dict[Npr_matrix]
453        extracted Bilinears
454    """
455
456    files, idx = _get_files(path, filestem, idl)
457
458    mom_in = None
459    mom_out = None
460
461    corr_data = {}
462    for hd5_file in files:
463        file = h5py.File(path + '/' + hd5_file, "r")
464        for i in range(16):
465            name = file['Bilinear/Bilinear_' + str(i) + '/info'].attrs['gamma'][0].decode('UTF-8')
466            if name not in corr_data:
467                corr_data[name] = []
468            raw_data = file['Bilinear/Bilinear_' + str(i) + '/corr'][0][0].view('complex')
469            corr_data[name].append(raw_data)
470            if mom_in is None:
471                mom_in = np.array(str(file['Bilinear/Bilinear_' + str(i) + '/info'].attrs['pIn'])[3:-2].strip().split(), dtype=float)
472            if mom_out is None:
473                mom_out = np.array(str(file['Bilinear/Bilinear_' + str(i) + '/info'].attrs['pOut'])[3:-2].strip().split(), dtype=float)
474
475        file.close()
476
477    result_dict = {}
478
479    for key, data in corr_data.items():
480        local_data = np.array(data)
481
482        rolled_array = np.rollaxis(local_data, 0, 5)
483
484        matrix = np.empty((rolled_array.shape[:-1]), dtype=object)
485        for si, sj, ci, cj in np.ndindex(rolled_array.shape[:-1]):
486            real = Obs([rolled_array[si, sj, ci, cj].real], [ens_id], idl=[idx])
487            imag = Obs([rolled_array[si, sj, ci, cj].imag], [ens_id], idl=[idx])
488            matrix[si, sj, ci, cj] = CObs(real, imag)
489
490        result_dict[key] = Npr_matrix(matrix, mom_in=mom_in, mom_out=mom_out)
491
492    return result_dict

Read hadrons Bilinear hdf5 file and output an array of CObs

Parameters
  • path (str): path to the files to read
  • filestem (str): namestem of the files to read
  • ens_id (str): name of the ensemble, required for internal bookkeeping
  • idl (range): If specified only configurations in the given range are read in.
Returns
  • result_dict (dict[Npr_matrix]): extracted Bilinears
def read_Fourquark_hd5(path, filestem, ens_id, idl=None, vertices=None):
495def read_Fourquark_hd5(path, filestem, ens_id, idl=None, vertices=None):
496    """Read hadrons FourquarkFullyConnected hdf5 file and output an array of CObs
497
498    Parameters
499    ----------
500    path : str
501        path to the files to read
502    filestem : str
503        namestem of the files to read
504    ens_id : str
505        name of the ensemble, required for internal bookkeeping
506    idl : range
507        If specified only configurations in the given range are read in.
508    vertices : list
509        Vertex functions to be extracted.
510
511    Returns
512    -------
513    result_dict : dict
514        extracted fourquark matrizes
515    """
516
517    if vertices is None:
518        vertices = ["VA", "AV"]
519
520    files, idx = _get_files(path, filestem, idl)
521
522    mom_in = None
523    mom_out = None
524
525    vertex_names = []
526    for vertex in vertices:
527        vertex_names += _get_lorentz_names(vertex)
528
529    corr_data = {}
530
531    tree = 'FourQuarkFullyConnected/FourQuarkFullyConnected_'
532
533    for hd5_file in files:
534        file = h5py.File(path + '/' + hd5_file, "r")
535
536        for i in range(32):
537            name = (file[tree + str(i) + '/info'].attrs['gammaA'][0].decode('UTF-8'), file[tree + str(i) + '/info'].attrs['gammaB'][0].decode('UTF-8'))
538            if name in vertex_names:
539                if name not in corr_data:
540                    corr_data[name] = []
541                raw_data = file[tree + str(i) + '/corr'][0][0].view('complex')
542                corr_data[name].append(raw_data)
543                if mom_in is None:
544                    mom_in = np.array(str(file[tree + str(i) + '/info'].attrs['pIn'])[3:-2].strip().split(), dtype=float)
545                if mom_out is None:
546                    mom_out = np.array(str(file[tree + str(i) + '/info'].attrs['pOut'])[3:-2].strip().split(), dtype=float)
547
548        file.close()
549
550    intermediate_dict = {}
551
552    for vertex in vertices:
553        lorentz_names = _get_lorentz_names(vertex)
554        for v_name in lorentz_names:
555            if v_name in [('SigmaXY', 'SigmaZT'),
556                          ('SigmaXT', 'SigmaYZ'),
557                          ('SigmaYZ', 'SigmaXT'),
558                          ('SigmaZT', 'SigmaXY')]:
559                sign = -1
560            else:
561                sign = 1
562            if vertex not in intermediate_dict:
563                intermediate_dict[vertex] = sign * np.array(corr_data[v_name])
564            else:
565                intermediate_dict[vertex] += sign * np.array(corr_data[v_name])
566
567    result_dict = {}
568
569    for key, data in intermediate_dict.items():
570
571        rolled_array = np.moveaxis(data, 0, 8)
572
573        matrix = np.empty((rolled_array.shape[:-1]), dtype=object)
574        for index in np.ndindex(rolled_array.shape[:-1]):
575            real = Obs([rolled_array[index].real], [ens_id], idl=[idx])
576            imag = Obs([rolled_array[index].imag], [ens_id], idl=[idx])
577            matrix[index] = CObs(real, imag)
578
579        result_dict[key] = Npr_matrix(matrix, mom_in=mom_in, mom_out=mom_out)
580
581    return result_dict

Read hadrons FourquarkFullyConnected hdf5 file and output an array of CObs

Parameters
  • path (str): path to the files to read
  • filestem (str): namestem of the files to read
  • ens_id (str): name of the ensemble, required for internal bookkeeping
  • idl (range): If specified only configurations in the given range are read in.
  • vertices (list): Vertex functions to be extracted.
Returns
  • result_dict (dict): extracted fourquark matrizes