Source code for pyicat_plus.apps.icat_as_nexus
import sys
import logging
import argparse
import datetime
from typing import Mapping, Union, Optional
import h5py
import numpy
from ..utils.log_utils import basic_config
from ..metadata.nexus import create_nxtreedict
from ..metadata.definitions import load_icat_fields
logger = logging.getLogger(__name__)
[docs]
def save_icat_as_nexus(filename: str, url: Optional[str] = None) -> None:
icat_fields = load_icat_fields(url=url)
metadict = _example_icat_metadata_as_dict(icat_fields)
nxtreedict = create_nxtreedict(
metadict, icat_fields=icat_fields, add_icat_attrs=True
)
with h5py.File(filename, "w") as nxroot:
nxroot.attrs["NX_class"] = "NXroot"
_dicttonx("entryname", nxtreedict, nxroot)
def _example_icat_metadata_as_dict(icat_fields) -> dict:
"""Example ICAT field values are generated based on the data type."""
now = datetime.datetime.now()
values = {
"NX_CHAR": lambda name: name,
"NX_DATE_TIME": lambda name: (
now + datetime.timedelta(minutes=len(name))
).isoformat(),
"NX_FLOAT64": lambda name: numpy.float64(len(name) + 0.001),
"NX_FLOAT": lambda name: numpy.float32(len(name) + 0.1),
}
metadict = dict()
for field in icat_fields.iter_fields():
value_gen = values[field.nxtype]
field_name = field.field_name
metadict[field_name] = value_gen(field_name)
return metadict
def _dicttonx(
name: str, value: Union[Mapping, str, float], h5group: h5py.Group
) -> None:
if "@" in name:
assert isinstance(value, str), f"Attribute {name} must be a string"
dsetname, _, attrname = name.rpartition("@")
if dsetname:
h5item = h5group[dsetname]
else:
h5item = h5group
h5item.attrs[attrname] = value
return
assert "@" not in name, f"Item {name} cannot have an '@' character"
if isinstance(value, Mapping):
h5group = h5group.create_group(name)
for name, value in value.items():
_dicttonx(name, value, h5group)
else:
h5group[name] = value
[docs]
def main(argv=None):
basic_config(logger=logger, level=logging.DEBUG, format="%(message)s")
if argv is None:
argv = sys.argv
parser = argparse.ArgumentParser(
description="Save ICAT definitions in a NeXus compliant HDF5 file"
)
parser.add_argument(
"--filename",
type=str,
required=False,
default="icat.h5",
help="File name to store the ICAT definitions",
)
parser.add_argument(
"--url", type=str, required=False, help="URL of the ICAT definitions"
)
args = parser.parse_args(argv[1:])
save_icat_as_nexus(args.filename, args.url)
logger.info(f"NeXus compliant HDF5 file created: '{args.filename}'")
if __name__ == "__main__":
sys.exit(main())