1import numpy as np
2
3from yt.utilities.logger import ytLogger as mylog
4
5
6def parse_unit_dimension(unit_dimension):
7    r"""Transforms an openPMD unitDimension into a string.
8
9    Parameters
10    ----------
11    unit_dimension : array_like
12        integer array of length 7 with one entry for the dimensional component of every
13        SI unit
14
15        [0] length L,
16        [1] mass M,
17        [2] time T,
18        [3] electric current I,
19        [4] thermodynamic temperature theta,
20        [5] amount of substance N,
21        [6] luminous intensity J
22
23    References
24    ----------
25
26    https://github.com/openPMD/openPMD-standard/blob/latest/STANDARD.md#unit-systems-and-dimensionality
27
28
29    Returns
30    -------
31    str
32
33    Examples
34    --------
35    >>> velocity = [1.0, 0.0, -1.0, 0.0, 0.0, 0.0, 0.0]
36    >>> print(parse_unit_dimension(velocity))
37    'm**1*s**-1'
38
39    >>> magnetic_field = [0.0, 1.0, -2.0, -1.0, 0.0, 0.0, 0.0]
40    >>> print(parse_unit_dimension(magnetic_field))
41    'kg**1*s**-2*A**-1'
42    """
43    if len(unit_dimension) != 7:
44        mylog.error("SI must have 7 base dimensions!")
45    unit_dimension = np.asarray(unit_dimension, dtype="int64")
46    dim = []
47    si = ["m", "kg", "s", "A", "C", "mol", "cd"]
48    for i in np.arange(7):
49        if unit_dimension[i] != 0:
50            dim.append(f"{si[i]}**{unit_dimension[i]}")
51    return "*".join(dim)
52
53
54def is_const_component(record_component):
55    """Determines whether a group or dataset in the HDF5 file is constant.
56
57    Parameters
58    ----------
59    record_component : h5py.Group or h5py.Dataset
60
61    Returns
62    -------
63    bool
64        True if constant, False otherwise
65
66    References
67    ----------
68    .. https://github.com/openPMD/openPMD-standard/blob/latest/STANDARD.md,
69       section 'Constant Record Components'
70    """
71    return "value" in record_component.attrs.keys()
72
73
74def get_component(group, component_name, index=0, offset=None):
75    """Grabs a dataset component from a group as a whole or sliced.
76
77    Parameters
78    ----------
79    group : h5py.Group
80    component_name : str
81        relative path of the component in the group
82    index : int, optional
83        first entry along the first axis to read
84    offset : int, optional
85        number of entries to read
86        if not supplied, every entry after index is returned
87
88    Notes
89    -----
90    This scales every entry of the component with the respective "unitSI".
91
92    Returns
93    -------
94    ndarray
95        (N,) 1D in case of particle data
96        (O,P,Q) 1D/2D/3D in case of mesh data
97    """
98    record_component = group[component_name]
99    unit_si = record_component.attrs["unitSI"]
100    if is_const_component(record_component):
101        shape = np.asarray(record_component.attrs["shape"])
102        if offset is None:
103            shape[0] -= index
104        else:
105            shape[0] = offset
106        # component is constant, craft an array by hand
107        return np.full(shape, record_component.attrs["value"] * unit_si)
108    else:
109        if offset is not None:
110            offset += index
111        # component is a dataset, return it (possibly masked)
112        return np.multiply(record_component[index:offset], unit_si)
113