Source code for mass.core.channel_group_hdf5_only
"""
Functions related to using a group of data sets where the raw (LJH) files are
not used, but the HDF5 files created from them are available.
"""
import os
import h5py
from . import channel_group
from . import channel
[docs]
def hdf5jl_name_from_ljh_name(ljh_name):
b, _ext = os.path.splitext(ljh_name)
return b + "_jl.hdf5"
[docs]
def make_or_get_master_hdf5_from_julia_hdf5_file(hdf5_filenames=None, forceNew=False,
require_clean_exit=True):
h5master_fname = channel_group._generate_hdf5_filename(hdf5_filenames[0])
if os.path.isfile(h5master_fname):
if forceNew:
os.remove(h5master_fname)
else:
print("REUSING THE EXISTING MASTER HDF5 FILE, %s" % h5master_fname)
return h5master_fname
with h5py.File(h5master_fname, "a") as master_hdf5_file: # noqa: PLR1702
with h5py.File(hdf5_filenames[0], "r") as single_channel_file:
# put the data where python mass expects it
master_hdf5_file.attrs["nsamples"] = single_channel_file["samples_per_record"].value
master_hdf5_file.attrs["npresamples"] = single_channel_file["pretrig_nsamples"].value
master_hdf5_file.attrs["frametime"] = single_channel_file["filter/frametime"].value
for h5fname in hdf5_filenames:
i = h5fname.find("_chan")
channum = int(h5fname[i + 5:-8])
try:
with h5py.File(h5fname, "r+") as single_channel_file:
if ("clean_exit_posix_timestamp_s" in single_channel_file
or not require_clean_exit) and len(single_channel_file["filt_value"][:]) > 1:
if "channum" not in single_channel_file.attrs.keys():
single_channel_file.attrs["channum"] = channum
if "npulses" not in single_channel_file.attrs.keys():
single_channel_file.attrs["npulses"] = len(
single_channel_file["filt_value"])
single_channel_file.attrs["filename"] = h5fname
master_hdf5_file["chan%i" % channum] = h5py.ExternalLink(h5fname, "/")
except KeyError:
print("failed to load chan %d hdf5 only" % channum)
return h5master_fname
[docs]
class TESGroupHDF5(channel_group.TESGroup):
"""Represent a TESGroup, except where the raw LJH files are not available."""
def __init__(self, h5master_fname, read_only=False):
if not os.path.isfile(h5master_fname):
raise Exception("file %s does not exist", h5master_fname)
elif read_only:
self.hdf5_file = h5py.File(h5master_fname, "r")
elif not read_only:
self.hdf5_file = h5py.File(h5master_fname, "a")
self.nPresamples = self.hdf5_file.attrs["npresamples"]
self.nSamples = self.hdf5_file.attrs["nsamples"]
self.timebase = self.hdf5_file.attrs["frametime"]
self.cut_field_desc_init()
dset_list = []
for key in self.hdf5_file.keys():
if not key.startswith("chan"):
continue
grp = self.hdf5_file[key]
pulserec_dict = {"nSamples": self.nSamples,
"nPresamples": self.nPresamples,
"timebase": self.timebase,
"nPulses": len(grp["filt_value"]),
"channum": grp.attrs["channum"],
"timestamp_offset": 0,
"filename": "from HDF5 file: " + self.hdf5_file.filename}
dset_list.append(channel.MicrocalDataSet(pulserec_dict, tes_group=self, hdf5_group=grp))
# Sort datasets by channel number
self.datasets = tuple(sorted(dset_list, key=lambda ds: ds.channum))
self._bad_channums = {}
self.fix_timestamps()
self.n_channels = len(dset_list)
[docs]
def fix_timestamps(self):
"""Mass expects p_timestamp to have units of seconds and be a float,
sometimes we save microsecond units as ints. This is a way to give mass
what it expects."""
for ds in self:
grp = ds.hdf5_group
if "timestamp_posix_usec" in grp:
ds.p_timestamp = grp["timestamp_posix_usec"][:] * 1e-6
def __repr__(self):
return f"{self.__class__.__name__:s}(hdf5_file={os.path.realpath(self.hdf5_file.filename):s})"