Source code for jungfrau_utils.swissfel_helpers
from __future__ import annotations
import re
from datetime import datetime, timedelta
from pathlib import Path
import h5py
[docs]
def locate_gain_file(file_path: str, *, detector_name: str = "", verbose: bool = True) -> str:
"""Locate gain file in default location at swissfel.
The default gain file location is
`/sf/jungfrau/config/gainMaps/<detector>/gains.h5``.
Args:
file_path (str): File path of a jungfrau data file.
detector_name (str, optional): Name of a detector, which gain file should be located if
there are multiple detectors' data present in the file. If empty, the file must contain
data for a single detector only. Defaults to ''.
verbose (bool, optional): Print info about located gain file.
Returns:
str: A path to the located gain file.
"""
_file_path = Path(file_path)
if not detector_name:
detector_name = get_single_detector_name(str(_file_path))
gain_path = Path("/sf/jungfrau/config/gainMaps/")
gain_file = gain_path.joinpath(detector_name, "gains.h5")
if not gain_file.is_file():
raise ValueError(
f"Gain file needs to be specified explicitly. No gain file in the default location: {gain_path}"
)
if verbose:
print(f"Auto-located gain file: {gain_file}")
return str(gain_file)
[docs]
def locate_pedestal_file(file_path: str, *, detector_name: str = "", verbose: bool = True) -> str:
"""Locate pedestal file in default location at swissfel.
The default pedestal file paths for a particula p-group are
``<prefix_path>/sf/<beamline>/data/<p-group>/res/JF_pedestals/`` (old daq)
or
``<prefix_path>/sf/<beamline>/data/<p-group>/raw/JF_pedestals/`` (new daq),
where <prefix_path> is a non-empty string in case of data retrieved from archive.
Args:
file_path (str): File path of a jungfrau data file.
detector_name (str, optional): Name of a detector, which pedestal file should be located if
there are multiple detectors' data present in the file. If empty, the file must contain
data for a single detector only. Defaults to ''.
verbose (bool, optional): Print info about located pedestal file.
Returns:
str: A path to the located pedestal file.
"""
_file_path = Path(file_path)
if not detector_name:
detector_name = get_single_detector_name(str(_file_path))
match = re.search(r"/sf/([a-zA-Z]+)/data/p(\d+)/raw/", file_path)
if match is None:
raise ValueError("Pedestal file needs to be specified explicitly.")
data_path = file_path[: match.end()]
pedestal_paths = (
Path(data_path).joinpath("JF_pedestals"),
Path(data_path[:-4]).joinpath("res/JF_pedestals"), # replace "raw/" with "res/"
)
# find a pedestal file, which was created closest in time to the jungfrau file
jf_file_mtime = _file_path.stat().st_mtime
closest_pedestal_file = ""
min_mtime_diff = float("inf")
for pedestal_path in pedestal_paths:
if pedestal_path.exists():
for entry in pedestal_path.iterdir():
if entry.is_file() and f"{detector_name}.res.h5" in entry.name:
time_diff = jf_file_mtime - entry.stat().st_mtime
if abs(time_diff) < abs(min_mtime_diff):
min_mtime_diff = time_diff
pedestal_mtime = entry.stat().st_mtime
closest_pedestal_file = entry
if not closest_pedestal_file:
raise ValueError(
f"Pedestal file needs to be specified explicitly. No pedestal file found in default locations: {pedestal_paths}"
)
if verbose:
print(f"Auto-located pedestal file: {closest_pedestal_file}")
mtime_diff = min_mtime_diff
if mtime_diff < 0:
# timedelta doesn't work nicely with negative values
# https://docs.python.org/3/library/datetime.html#datetime.timedelta.resolution
tdelta_str = "-" + str(timedelta(seconds=-mtime_diff))
else:
tdelta_str = str(timedelta(seconds=mtime_diff))
print(f"jungfrau file: {datetime.fromtimestamp(jf_file_mtime).strftime('%H:%M %d.%m.%Y')}")
print(f"pedestal file: {datetime.fromtimestamp(pedestal_mtime).strftime('%H:%M %d.%m.%Y')}")
print(" mtime difference: " + tdelta_str)
return str(closest_pedestal_file)
[docs]
def get_single_detector_name(file_path: str) -> str:
"""Get detector name from file that contains only single detector data.
Args:
file_path (str): File path of a jungfrau data file.
Returns:
str: Name of single detector in file.
"""
with h5py.File(file_path, "r") as h5f:
n_groups = 0
for name, obj in h5f["/data"].items():
if isinstance(obj, h5py.Group):
n_groups += 1
detector_name = name
# raise an exception if n_groups != 1
if n_groups == 0:
raise ValueError("File doesn't contain detector data.")
if n_groups > 1:
raise ValueError(
"Specify `detector_name` as the file contains data for multiple detectors."
)
return detector_name