コード例 #1
0
    def __array_finalize__(self, obj):
        # according to numpy documentation:
        #  __array__finalize__(self, obj) is called whenever the system
        #  internally allocates a new array from obj, where obj is a
        #  subclass (subtype) of the (big)ndarray. It can be used to
        #  change attributes of self after construction (so as to ensure
        #  a 2-d matrix for example), or to update meta-information from
        #  the parent. Subclasses inherit a default implementation of
        #  this method that does nothing.
        if obj is None:
            return

        # Define _info attribute
        # - getattr() searches obj for the '_info' attribute. If the
        #   attribute exists, then it's returned. If the attribute does
        #   NOT exist, then the 3rd arg is returned as a default value.
        self._info = getattr(
            obj, '_info', {
                'hdf file': None,
                'dataset name': None,
                'dataset path': None,
                'configuration name': None,
                'adc': None,
                'bit': None,
                'sample rate': (None, 'MHz'),
                'sample average': None,
                'shot average': None,
                'board': None,
                'channel': None,
                'voltage offset': None,
                'probe name': None,
                'port': (None, None),
                'signal units': '',
                'added controls': []
            })

        # Define plasma attribute
        self._plasma = getattr(
            obj, '_plasma', {
                'Bo': None,
                'kT': None,
                'kTe': None,
                'kTi': None,
                'gamma': core.FloatUnit(1.0, 'arb'),
                'm_e': core.ME,
                'm_i': None,
                'n': None,
                'n_e': None,
                'n_i': None,
                'Z': None
            })
コード例 #2
0
ファイル: hdfreaddata.py プロジェクト: rocco8773/bapsflib
    def __array_finalize__(self, obj):
        # This should only be True during explicit construction
        # if obj is None:
        if obj is None or obj.__class__ is np.ndarray:
            return

        # Define _info attribute
        self._info = getattr(
            obj,
            "_info",
            {
                "source file": None,
                "device group path": None,
                "device dataset path": None,
                "configuration name": None,
                "adc": None,
                "bit": None,
                "clock rate": None,
                "sample average": None,
                "shot average": None,
                "board": None,
                "channel": None,
                "voltage offset": None,
                "probe name": None,
                "port": (None, None),
                "signal units": None,
                "controls": {},
            },
        )

        # Define plasma attribute
        self._plasma = getattr(
            obj,
            "_plasma",
            {
                "Bo": None,
                "kT": None,
                "kTe": None,
                "kTi": None,
                "gamma": core.FloatUnit(1.0, "arb"),
                "m_e": core.ME,
                "m_i": None,
                "n": None,
                "n_e": None,
                "n_i": None,
                "Z": None,
            },
        )  # pragma: no cover
コード例 #3
0
ファイル: hdfreaddata.py プロジェクト: gkbal/bapsflib
    def __array_finalize__(self, obj):
        # This should only be True during explicit construction
        # if obj is None:
        if obj is None or obj.__class__ is np.ndarray:
            return

        # Define _info attribute
        self._info = getattr(
            obj, '_info', {
                'source file': None,
                'device group path': None,
                'device dataset path': None,
                'configuration name': None,
                'adc': None,
                'bit': None,
                'clock rate': None,
                'sample average': None,
                'shot average': None,
                'board': None,
                'channel': None,
                'voltage offset': None,
                'probe name': None,
                'port': (None, None),
                'signal units': None,
                'controls': {},
            })

        # Define plasma attribute
        self._plasma = getattr(
            obj, '_plasma', {
                'Bo': None,
                'kT': None,
                'kTe': None,
                'kTi': None,
                'gamma': core.FloatUnit(1.0, 'arb'),
                'm_e': core.ME,
                'm_i': None,
                'n': None,
                'n_e': None,
                'n_i': None,
                'Z': None
            })  # pragma: no cover
コード例 #4
0
ファイル: hdfreaddata.py プロジェクト: gkbal/bapsflib
    def set_plasma_value(self, key, value):  # pragma: no cover
        """
        Re-define one of the base plasma values (Bo, gamma, kT, kTe,
        kTi, m_i, n, n_e, or Z) in the :attr:`plasma` dictionary.

        :param str key: one of the base plasma values
        :param value: value for key
        """
        # set plasma value
        if key == 'Bo':
            self._plasma['Bo'] = core.FloatUnit(value, 'G')
        elif key == 'gamma':
            self._plasma['gamma'] = core.FloatUnit(value, 'arb')
        elif key in ['kT', 'kTe', 'kTi']:
            self._plasma[key] = core.FloatUnit(value, 'eV')

            if key == 'kTe' and self._plasma['kt'] is None:
                self._plasma['kT'] = self._plasma[key]
        elif key == 'm_i':
            self._plasma[key] = core.FloatUnit(value, 'g')
        elif key in ['n', 'n_e']:
            self._plasma[key] = core.FloatUnit(value, 'cm^-3')

            # re-calc n_i and n
            if key == 'n_e':
                self._plasma['n_i'] = core.FloatUnit(
                    self._plasma['n_e'] / self._plasma['Z'], 'cm^-3')

                if self._plasma['n'] is None:
                    self._plasma['n'] = self._plasma['n_e']
        elif key == 'Z':
            self._plasma[key] = core.IntUnit(value, 'arb')

            # re-calc n_i
            self._plasma['n_i'] = \
                core.FloatUnit(self._plasma['n_e'] / self._plasma['Z'],
                               'cm^-3')

        # update key plasma constants
        self._update_plasma_constants()
コード例 #5
0
ファイル: hdfreaddata.py プロジェクト: rocco8773/bapsflib
    def set_plasma_value(self, key, value):  # pragma: no cover
        """
        Re-define one of the base plasma values (Bo, gamma, kT, kTe,
        kTi, m_i, n, n_e, or Z) in the :attr:`plasma` dictionary.

        :param str key: one of the base plasma values
        :param value: value for key
        """
        # set plasma value
        if key == "Bo":
            self._plasma["Bo"] = core.FloatUnit(value, "G")
        elif key == "gamma":
            self._plasma["gamma"] = core.FloatUnit(value, "arb")
        elif key in ["kT", "kTe", "kTi"]:
            self._plasma[key] = core.FloatUnit(value, "eV")

            if key == "kTe" and self._plasma["kt"] is None:
                self._plasma["kT"] = self._plasma[key]
        elif key == "m_i":
            self._plasma[key] = core.FloatUnit(value, "g")
        elif key in ["n", "n_e"]:
            self._plasma[key] = core.FloatUnit(value, "cm^-3")

            # re-calc n_i and n
            if key == "n_e":
                self._plasma["n_i"] = core.FloatUnit(
                    self._plasma["n_e"] / self._plasma["Z"], "cm^-3")

                if self._plasma["n"] is None:
                    self._plasma["n"] = self._plasma["n_e"]
        elif key == "Z":
            self._plasma[key] = core.IntUnit(value, "arb")

            # re-calc n_i
            self._plasma["n_i"] = core.FloatUnit(
                self._plasma["n_e"] / self._plasma["Z"], "cm^-3")

        # update key plasma constants
        self._update_plasma_constants()
コード例 #6
0
ファイル: hdfreaddata.py プロジェクト: gkbal/bapsflib
    def set_plasma(self,
                   Bo,
                   kTe,
                   kTi,
                   m_i,
                   n_e,
                   Z,
                   gamma=None,
                   **kwargs):  # pragma: no cover
        """
        Set :attr:`plasma` and add key frequency, length, and velocity
        parameters. (all quantities in cgs except temperature is in eV)

        :param float Bo: magnetic field (in Gauss)
        :param float kTe: electron temperature (in eV)
        :param float kTi: ion temperature (in eV)
        :param float m_i: ion mass (in g)
        :param float n_e: electron number density (in cm^-3)
        :param int Z: ion charge number
        :param float gamma: adiabatic index (arb.)
        """
        # define base values
        self._plasma['Bo'] = core.FloatUnit(Bo, 'G')
        self._plasma['kTe'] = core.FloatUnit(kTe, 'eV')
        self._plasma['kTi'] = core.FloatUnit(kTi, 'eV')
        self._plasma['m_i'] = core.FloatUnit(m_i, 'g')
        self._plasma['n_e'] = core.FloatUnit(n_e, 'cm^-3')
        self._plasma['Z'] = core.IntUnit(Z, 'arb')

        # define ion number density
        self._plasma['n_i'] = core.FloatUnit(
            self._plasma['n_e'] / self._plasma['Z'], 'cm^-3')

        # define gamma (adiabatic index)
        # - default = 1.0
        if gamma is not None:
            self._plasma['gamma'] = core.FloatUnit(gamma, 'arb')

        # define plasma temperature
        # - if omitted then assumed kTe
        # TODO: double check assumption
        if 'kT' in kwargs:
            self._plasma['kT'] = core.FloatUnit(kwargs['kT'], 'eV')
        else:
            self._plasma['kT'] = core.FloatUnit(kTe, 'eV')

        # define plasma number density
        # - if omitted then assumed n_e
        if 'n' in kwargs:
            self._plasma['n'] = core.FloatUnit(kwargs['n'], 'cm^-3')
        else:
            self._plasma['n'] = core.FloatUnit(n_e, 'cm^-3')

        # add key plasma constants
        self._update_plasma_constants()
コード例 #7
0
ファイル: hdfreaddata.py プロジェクト: gkbal/bapsflib
    def __new__(cls,
                hdf_file: File,
                board: int,
                channel: int,
                index=slice(None),
                shotnum=slice(None),
                digitizer=None,
                config_name=None,
                adc=None,
                keep_bits=False,
                add_controls=None,
                intersection_set=True,
                **kwargs):
        """
        :param hdf_file: HDF5 file object
        :param board: analog-digital-converter board number
        :param channel: analog-digital-converter channel number
        :param index: dataset row indices to be sliced (overridden
            by :code:`shotnum`)
        :type index: Union[int, List[int], slice, numpy.ndarray]
        :param shotnum: HDF5 file shot number(s) indicating data
            entries to be extracted (overrides :code:`index`)
        :type shotnum: Union[int, List[int], slice, numpy.ndarray]
        :param str digitizer: digitizer name
        :param str adc: name of analog-digital-converter
        :param str config_name: name of the digitizer configuration
        :param bool keep_bits: set :code:`True` to keep data in bits,
            :code:`False` (DEFAULT) to convert data to voltage
        :param add_controls: a list indicating the desired control
            device names and their configuration name (if more than one
            configuration exists)
        :type controls: Union[str, Iterable[str, Tuple[str, Any]]]
        :param bool intersection_set: :code:`True` (DEFAULT) will force
            the returned shot numbers to be the intersection of
            :data:`shotnum` and the shot numbers contained in each
            control device and digitizer dataset. :code:`False` will
            return the union of shot numbers.

        Behavior of :data:`index`, :data:`shotnum` and
        :data:`intersection_set`:

        .. note::

            * The :data:`shotnum` keyword will always override the
              :data:`index` keyword, but, due to extra overhead
              required for identifying shot number locations in the
              digitizer dataset, the :data:`index` keyword will always
              execute quicker than the :data:`shotnum` keyword.
        """
        # initialize timing
        tt = []
        if 'timeit' in kwargs:  # pragma: no cover
            timeit = kwargs['timeit']
            if timeit:
                tt.append(time.time())
            else:
                timeit = False
        else:
            timeit = False

        # ---- Condition hdf_file                                   ----
        # - `hdf_file` is a lapd.File object
        #
        if not isinstance(hdf_file, File):
            raise TypeError("`hdf_file` is NOT type `" + File.__module__ +
                            "." + File.__qualname__ + "`")

        # print execution timing
        if timeit:  # pragma: no cover
            tt.append(time.time())
            print('tt - `hdf_file` conditioning: '
                  '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # ---- Examine file map object                              ----
        # grab instance of `HDFMap`
        _fmap = hdf_file.file_map

        # ---- Condition `add_controls`                             ----
        # Check for non-empty controls
        if bool(add_controls) and not bool(_fmap.controls):
            raise ValueError('There are no control devices in the HDF5 file.')

        # condition controls
        if bool(add_controls):
            controls = condition_controls(hdf_file, add_controls)
        else:
            controls = []

        # print execution timing
        if timeit:  # pragma: no cover
            tt.append(time.time())
            print('tt - `add_controls` conditioning: '
                  '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # ---- Condition `digitizer` keyword                        ----
        if not bool(_fmap.digitizers):
            raise ValueError("There are no digitizers in the HDF5 file.")
        elif digitizer is None:
            if not bool(_fmap.main_digitizer):
                raise ValueError("No main digitizer is identified..."
                                 "need to specify `digitizer` kwarg")

            why = ("Digitizer not specified so assuming the "
                   "'main_digitizer' "
                   "({})".format(_fmap.main_digitizer.device_name) +
                   " defined in the mappings.")
            warn(why)
            _dmap = _fmap.main_digitizer
        else:
            try:
                _dmap = _fmap.digitizers[digitizer]
            except KeyError:
                raise ValueError("Specified Digitizer '{}'".format(digitizer) +
                                 " is not among known digitizers "
                                 "({})".format(list(_fmap.digitizers)))

        # ---- Gather Digi Dataset Info                             ----
        #
        # Note: _dmap.construct_dataset_name has conditioning for
        #       board, channel, adc, and
        #
        # dname      - digitizer dataset name
        # dhname     - digitizer header dataset name
        # dpath      - full path to digitizer group
        # dset       - digitizer h5py.Dataset object
        # dheader    - dset associated header dataset
        # shotnumkey - field name for shot number column in dheader
        #
        # Build kwargs for construct_dataset_name()
        kwargs = {'return_info': True}
        if config_name is not None:
            kwargs['config_name'] = config_name
        if adc is not None:
            kwargs['adc'] = adc

        # Get datasets
        dname, d_info = _dmap.construct_dataset_name(board, channel, **kwargs)
        dhname = _dmap.construct_header_dataset_name(board, channel, **kwargs)
        dpath = _dmap.info['group path'] + '/'
        dset = hdf_file.get(dpath + dname)
        dheader = hdf_file.get(dpath + dhname)

        # define `config_name`
        if config_name is None:
            config_name = _dmap.active_configs[0]

        # define `shotnumkey`
        shotnumkey = \
            _dmap.configs[config_name]['shotnum']['dset field'][0]

        # print execution timing
        if timeit:  # pragma: no cover
            tt.append(time.time())
            print('tt - get dset and dheader: '
                  '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # ---- Condition shots, index, and shotnum ----
        # index   -- row index of digitizer dataset
        #            ~ indexed at 0
        #            ~ supersedes any other indexing keywords
        # shotnum -- global HDF5 file shot number
        #            ~ this is the index used to link values between
        #              datasets
        #            ~ overridden by `index`
        #
        # Through conditioning the following are (re-)defined
        # index   -- row index of digitizer dataset (dset)
        #            ~ numpy.ndarray
        #            ~ dtype = np.integer
        #            ~ shape = (num_of_indices,)
        #
        # shotnum -- global HDF5 shot numbers
        #            ~ index at 1
        #            ~ will be a filtered version of input kwarg shotnum
        #              based on intersection_set
        #            ~ numpy.ndarray
        #            ~ dtype = np.uint32
        #            ~ shape = (sn_size, )
        #
        # sni     -- bool array for providing a one-to-one mapping
        #            between shotnum and index
        #            ~ shotnum[sni] = dheader[index, shotnumkey]
        #            ~ data['signal'][sni, ...] = dset[index, ...]
        #            ~ data['singal'][np.logical_not(sni), ...] = np.nan
        #            ~ numpy.ndarray
        #            ~ dtype = np.bool
        #            ~ shape = (sn_size, )
        #            ~ np.count_nonzero(arr[0,...]) = num_of_indices
        #
        # - Indexing behavior: (depends on intersection_set)
        #
        #   ~ intersection_set = True (DEFAULT)
        #     * the returned array will only contain shot numbers that
        #       are in the intersection of shotnum, the digitizer
        #       dataset, and all the specified control device datasets
        #
        #   ~ intersection_set = False
        #     * the returned array will contain all shot numbers
        #       specified by shotnum (>= 1)
        #     * if a dataset does not included a shot number contained
        #       in shotnum, then its entry in the returned array will
        #       be given a NULL value depending on the dtype
        #
        # Determine if indexing w.r.t. `index` or `shotnum`
        index_with = 'index'
        if isinstance(index, slice):
            if index == slice(None):
                if not isinstance(shotnum, slice):
                    index_with = 'shotnum'
                elif shotnum != slice(None):
                    index_with = 'shotnum'

        # Condition `index` and `shotnum` keywords
        # - Valid indexing types are: int, list(int), slice(), and
        #   np.ndarray
        #
        if index_with == 'index':
            # Condition `index` keyword
            #
            # Note: I'm letting the slicing of dset[index, shotnumkey]
            #       throw the appropriate errors
            #
            # Define `shotnum`
            # - Note: h5py datasets can NOT be sliced using numpy arrays
            #
            # convert `index` to np.ndarray
            sn_size = dheader.size
            if isinstance(index, int):
                index = np.array([index], dtype=np.int32)
            elif isinstance(index, list):
                index = np.array(index, dtype=np.int32)
            elif isinstance(index, slice):
                start, stop, step = index.indices(sn_size)
                index = np.arange(start, stop, step, dtype=np.int32)
            elif isinstance(index, type(Ellipsis)):
                index = np.arange(0, sn_size, 1, dtype=np.int32)
            elif isinstance(index, np.ndarray):
                pass
            else:
                raise TypeError("Valid `index` type not passed.")

            # convert (VALID) negative indices to positive
            neg_index_mask = np.where((index < 0) & (index >= -sn_size), True,
                                      False)
            if np.any(neg_index_mask):
                adj_ii = index[neg_index_mask] % sn_size
                index[neg_index_mask] = adj_ii
            index = np.unique(index)

            # define `shotnum`
            shotnum = dheader[index.tolist(), shotnumkey]

            # define sni
            sni = np.ones(shotnum.shape[0], dtype=np.bool)

            # print execution timing
            if timeit:  # pragma: no cover
                tt.append(time.time())
                print('tt - condition index: '
                      '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))
        else:
            # Condition `shotnum` keyword
            #
            # convert `shotnum` to np.ndarray
            '''
            if isinstance(shotnum, slice):
                # determine largest possible shot number
                last_sn = dheader[-1, shotnumkey]
                if shotnum.stop is not None:
                    stop_sn = max(shotnum.stop, last_sn + 1)
                else:
                    stop_sn = last_sn + 1

                # get the start, stop, and step for the shot number
                # array
                start, stop, step = shotnum.indices(stop_sn)

                # determine smallest possible shot number
                # - intersection_set = True
                #   * start = max of first_sn and shotnum.start
                # - intersection_set = False
                #   * start = min of first_sn and shotnum.start
                first_sn = [dheader[0, shotnumkey]]
                if shotnum.start is not None:
                    # ensure shot numbers are >= 1
                    if start <= 0:
                        start = 1
                else:
                    # start wasn't specified in slice object
                    start = min(first_sn)

                # adjust start for intersection_set
                if intersection_set:
                    first_sn.append(start)
                    start = max(first_sn)

                # re-define shotnum as a list
                shotnum = np.arange(start, stop, step).tolist()
            elif isinstance(shotnum, int):
                shotnum = [shotnum]
            elif isinstance(shotnum, list):
                # ensure all elements are int
                if not all(isinstance(sn, int) for sn in shotnum):
                    raise ValueError('Valid `shotnum` not passed')
            else:
                raise ValueError('Valid `shotnum` not passed')
            '''
            # perform `shotnum` conditioning
            # - `shotnum` is returned as a numpy array
            shotnum = condition_shotnum(shotnum, {'digi': dheader},
                                        {'digi': shotnumkey})

            # Calc. the corresponding `index` and `sni`
            # - `shotnum` will be converted from list to np.array
            # - `index` and `sni` will be np.array's
            '''
            index, shotnum, sni = \
                condition_shotnum(shotnum, dheader, shotnumkey,
                                  intersection_set)
            '''
            index, sni = build_sndr_for_simple_dset(shotnum, dheader,
                                                    shotnumkey)

            # perform intersection
            if intersection_set:
                shotnum, sni_dict, index_dict = \
                    do_shotnum_intersection(shotnum, {'digi': sni},
                                            {'digi': index})
                sni = sni_dict['digi']
                index = index_dict['digi']

            # print execution timing
            if timeit:  # pragma: no cover
                tt.append(time.time())
                print('tt - condition shotnum: '
                      '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # ---- Retrieve Control Data                                ----
        # 1. retrieve the numpy array for control data
        # 2. re-filter shotnum if intersection_set=True s.t. only
        #    shotnum's w/ control data are returned
        #
        # grab control device dataset
        #
        # - this will ensure cdata.shape == data.shape all the time
        # - shotnum should always be a ndarray at this point
        #
        if len(controls) != 0:
            cdata = HDFReadControls(hdf_file,
                                    controls,
                                    assume_controls_conditioned=True,
                                    shotnum=shotnum,
                                    intersection_set=intersection_set)

            # print execution timing
            if timeit:  # pragma: no cover
                tt.append(time.time())
                print('tt - read in cdata (control data): '
                      '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

            # re-filter index, shotnum, and sni
            # - only need to be filtered if intersection_set=True
            # - for intersection_set=True, shotnum and index are
            #   one-to-one
            #
            if intersection_set:
                new_sn_mask = np.isin(shotnum, cdata['shotnum'])
                shotnum = shotnum[new_sn_mask]
                index = index[new_sn_mask]
                sni = np.ones(shotnum.shape[0], dtype=bool)
        else:
            cdata = None

        # ---- Build `obj`                                          ----
        # Define dtype and shape
        # - 1st column of the digi data header contains the global HDF5
        #   file shot number
        # - shotkey = is the field name/key of the dheader shot number
        #   column
        sigtype = np.float32 if not keep_bits else dset.dtype
        shape = shotnum.shape
        dtype = [('shotnum', np.uint32, 1), ('signal', sigtype, dset.shape[1]),
                 ('xyz', np.float32, 3)]
        if len(controls) != 0:
            for subdtype in cdata.dtype.descr:
                if subdtype[0] not in [d[0] for d in dtype]:
                    dtype.append(subdtype)

        # print execution timing
        if timeit:  # pragma: no cover
            tt.append(time.time())
            print('tt - define dtype: '
                  '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # Initialize data array
        data = np.empty(shape, dtype=dtype)

        # print execution timing
        if timeit:  # pragma: no cover
            tt.append(time.time())
            print('tt - initialize data np.ndarray: '
                  '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # fill 'shotnum' field of data array
        data['shotnum'] = shotnum

        # fill 'signal' fields of data array
        index = index.tolist()
        if intersection_set:
            # fill signal
            data['signal'] = dset[index, ...]
        else:
            # fill signal
            data['signal'][sni] = dset[index, ...]
            if np.issubdtype(data['signal'].dtype, np.integer):
                data['signal'][np.logical_not(sni)] = 0
            else:
                # dtype is np.floating
                data['signal'][np.logical_not(sni)] = np.nan

        # fill fields related to controls
        if len(controls) != 0:
            # Note: shot numbers of cdata and data are one-to-one
            #       by this point so intersection_set is irrelevant
            #
            if not np.array_equal(data['shotnum'],
                                  cdata['shotnum']):  # pragma: no cover
                # this should never happen
                raise ValueError("data['shotnum'] and cdata['shotnum'] are not"
                                 " equal")

            # fill xyz
            if 'xyz' in cdata.dtype.names:
                data['xyz'] = cdata['xyz']
            else:
                data['xyz'] = np.nan

            # fill remaining controls
            for field in cdata.dtype.names:
                if field not in ('shotnum', 'xyz'):
                    data[field] = cdata[field]
        else:
            # fill xyz
            data['xyz'] = np.nan

        # print execution timing
        if timeit:  # pragma: no cover
            tt.append(time.time())
            print('tt - fill data array: '
                  '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # Define obj to be returned
        obj = data.view(cls)

        # get voltage offset
        try:
            voffset = dheader[0, 'Offset'] * u.volt
        except ValueError:
            warn("Digitizer header dataset is missing the voltage "
                 "'Offset' field. ")
            voffset = None

        # assign dataset meta-info
        obj._info = {
            'source file': os.path.abspath(hdf_file.filename),
            'device group path': _dmap.info['group path'],
            'device dataset path': dpath + dname,
            'digitizer': d_info['digitizer'],
            'configuration name': d_info['configuration name'],
            'adc': d_info['adc'],
            'bit': d_info['bit'],
            'clock rate': d_info['clock rate'],
            'sample average': d_info['sample average (hardware)'],
            'shot average': d_info['shot average (software)'],
            'board': board,
            'channel': channel,
            'voltage offset': voffset,
            'probe name': None,
            'port': (None, None),
            'signal units': u.bit,
        }
        if cdata is not None:
            obj._info['controls'] = \
                copy.deepcopy(cdata.info['controls'])
        else:
            obj._info['controls'] = {}

        # plasma parameter dict
        obj._plasma = {
            'Bo': None,
            'kT': None,
            'kTe': None,
            'kTi': None,
            'gamma': core.FloatUnit(1.0, 'arb'),
            'm_e': core.ME,
            'm_i': None,
            'n': None,
            'n_e': None,
            'n_i': None,
            'Z': None
        }  # pragma: no cover

        # convert to voltage
        # - 'signal' dtype is assigned based on keep_bit
        #
        # obj['signal'] = obj['signal'].astype(np.float32, copy=False)
        #
        if not keep_bits:
            if obj.dv is None:
                warn("Unable to calculated voltage step size..."
                     "'signal' remains as bits")
            else:
                # define offset
                offset = abs(obj.info['voltage offset'].value)

                # calc voltage
                obj['signal'] = (obj.dv.value * obj['signal']) - offset

                # update 'signal units'
                obj._info['signal units'] = u.volt

        # print execution timing
        if timeit:  # pragma: no cover
            tt.append(time.time())
            print('tt - execution time: '
                  '{} ms'.format((tt[-1] - tt[0]) * 1.E3))

        # return obj
        return obj
コード例 #8
0
ファイル: hdfreaddata.py プロジェクト: rocco8773/bapsflib
    def set_plasma(self,
                   Bo,
                   kTe,
                   kTi,
                   m_i,
                   n_e,
                   Z,
                   gamma=None,
                   **kwargs):  # pragma: no cover
        """
        Set :attr:`plasma` and add key frequency, length, and velocity
        parameters. (all quantities in cgs except temperature is in eV)

        :param float Bo: magnetic field (in Gauss)
        :param float kTe: electron temperature (in eV)
        :param float kTi: ion temperature (in eV)
        :param float m_i: ion mass (in g)
        :param float n_e: electron number density (in cm^-3)
        :param int Z: ion charge number
        :param float gamma: adiabatic index (arb.)
        """
        # define base values
        self._plasma["Bo"] = core.FloatUnit(Bo, "G")
        self._plasma["kTe"] = core.FloatUnit(kTe, "eV")
        self._plasma["kTi"] = core.FloatUnit(kTi, "eV")
        self._plasma["m_i"] = core.FloatUnit(m_i, "g")
        self._plasma["n_e"] = core.FloatUnit(n_e, "cm^-3")
        self._plasma["Z"] = core.IntUnit(Z, "arb")

        # define ion number density
        self._plasma["n_i"] = core.FloatUnit(
            self._plasma["n_e"] / self._plasma["Z"], "cm^-3")

        # define gamma (adiabatic index)
        # - default = 1.0
        if gamma is not None:
            self._plasma["gamma"] = core.FloatUnit(gamma, "arb")

        # define plasma temperature
        # - if omitted then assumed kTe
        # TODO: double check assumption
        if "kT" in kwargs:
            self._plasma["kT"] = core.FloatUnit(kwargs["kT"], "eV")
        else:
            self._plasma["kT"] = core.FloatUnit(kTe, "eV")

        # define plasma number density
        # - if omitted then assumed n_e
        if "n" in kwargs:
            self._plasma["n"] = core.FloatUnit(kwargs["n"], "cm^-3")
        else:
            self._plasma["n"] = core.FloatUnit(n_e, "cm^-3")

        # add key plasma constants
        self._update_plasma_constants()
コード例 #9
0
    def __new__(cls,
                hdf_file,
                board,
                channel,
                index=slice(None),
                shotnum=slice(None),
                digitizer=None,
                adc=None,
                config_name=None,
                keep_bits=False,
                add_controls=None,
                intersection_set=True,
                silent=False,
                **kwargs):
        """
        When inheriting from numpy, the object creation and
        initialization is handled by __new__ instead of __init__.

        :param hdf_file: object instance of the HDF5 file
        :type hdf_file: :class:`bapsflib.lapdhdf.files.File`
        :param int board: board number of data to be extracted
        :param int channel: channel number of data to be extracted
        :param index: row index/indices of dataset to be extracted
            (overridden by :code:`shotnum`)
        :type index: :code:`None`, int, list(int), or slice()
        :param shotnum: global HDF5 shot number (overrides
            :code:`index`)
        :type shotnum: :code:`None`, int, list(int), or slice()
        :param str digitizer: name of digitizer for which board and
            channel belong to
        :param str adc: name of analog-digital-converter in the
            digitizer for which board and channel belong to
        :param str config_name: name of the digitizer configuration to
            be used
        :param bool keep_bits: set :code:`True` to keep data in bits,
            :code:`False` (default) convert data to voltage
        :param add_controls: list of control devices whose data will
            be matched with the digitizer data
        :type add_controls: list of strings and/or 2-element tuples. If
            an element is a string, then the string is the control
            device name. If an element is a 2-element tuple, then
            tuple[0] is the control device name and tuple[1] is a unique
            specifier for that control device.
        :param bool intersection_set:
        :param bool silent: set :code:`True` to suppress command line
            print out of soft warnings

        .. note::

            Keyword :code:`shots` was renamed to :code:`index` in
            version 0.1.3.dev1.  Keyword :code:`shots` will still work,
            but will be deprecated in the future.
        """
        #
        # numpy uses __new__ to initialize objects, so an __init__ is
        # not necessary
        #

        # initialize timing
        tt = []
        if 'timeit' in kwargs:
            timeit = kwargs['timeit']
            if timeit:
                tt.append(time.time())
            else:
                timeit = False
        else:
            timeit = False

        # initiate warning string
        warn_str = ''

        # ---- Condition hdf_file ----
        # Check hdf_file is a lapdhdf.File object
        try:
            file_map = hdf_file.file_map
        except AttributeError:
            raise AttributeError('hdf_file needs to be of type lapdhdf.File')

        # Condition digitizer keyword
        if digitizer is None:
            warn_str = "** Warning: Digitizer not specified so " \
                + "assuming the 'main_digitizer' ({})".format(
                    file_map.main_digitizer.info[
                        'group name']) \
                + " defined in the mappings."
            digi_map = file_map.main_digitizer
        else:
            try:
                digi_map = hdf_file.file_map.digitizers[digitizer]
            except KeyError:
                raise ValueError('Specified Digitizer is not among '
                                 'known digitizers')

        # print execution timing
        if timeit:
            tt.append(time.time())
            print('tt - hdf_file conditioning: '
                  '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # ---- Check for Control Device Addition ---
        # condition controls
        if add_controls is not None:
            controls = condition_controls(hdf_file,
                                          add_controls,
                                          silent=silent)

            # check controls is not empty
            if not controls:
                warn_str = '\n** Warning: no valid controls passed, ' \
                           'none added to array'
                controls = []
        else:
            controls = []

        # print execution timing
        if timeit:
            tt.append(time.time())
            print('tt - add_controls conditioning: '
                  '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # ---- Gather Digi Dataset Info ----
        #
        # Note: digi_map.construct_dataset_name has conditioning for
        #       board, channel, adc, and
        #
        # dname      - digitizer dataset name
        # dhname     - digitizer header dataset name
        # dpath      - full path to digitizer group
        # dset       - digitizer h5py.Dataset object (data is still on
        #              disk)
        # dheader    - header dataset for the digitizer dataset, this
        #              has the shot number values
        # shotnumkey - field name for shot number column in the digi
        #              header dataset (dheader)
        #
        # Build kwargs for construct_dataset_name()
        kwargs = {'return_info': True, 'silent': silent}
        if config_name is not None:
            kwargs['config_name'] = config_name
        if adc is not None:
            kwargs['adc'] = adc

        # Get dataset
        dname, d_info = digi_map.construct_dataset_name(
            board, channel, **kwargs)
        dhname = digi_map.construct_header_dataset_name(
            board, channel, **kwargs)
        dpath = digi_map.info['group path'] + '/'
        dset = hdf_file.get(dpath + dname)
        dheader = hdf_file.get(dpath + dhname)
        shotnumkey = digi_map.shotnum_field

        # print execution timing
        if timeit:
            tt.append(time.time())
            print('tt - get dset and dheader: '
                  '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # ---- Condition `keep_bits` ----
        if 'Offset' not in dheader.dtype.names:
            # there's no voltage offset value to calculate dv
            if not keep_bits:
                warn('Could not find voltage offset, calculating '
                     'voltage without offset')

            # force keep_bits True
            keep_bits = True

        # print execution timing
        if timeit:
            tt.append(time.time())
            print('tt - condition keep_bits kwarg: '
                  '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # ---- Condition shots, index, and shotnum ----
        # shots   -- same as index (legacy, do NOT use)
        #            ~ overridden by index and shotnum
        #            ~ this is kept for backwards compatibility
        #            ~ 'shots' was renamed to 'index' in v0.1.3dev1
        # index   -- row index of digitizer dataset
        #            ~ indexed at 0
        #            ~ supersedes any other indexing keywords
        # shotnum -- global HDF5 file shot number
        #            ~ this is the index used to link values between
        #              datasets
        #            ~ overridden by `index`
        #
        # Through conditioning the following are defined (whether index
        # or shotnum is given):
        # index   -- row index of digitizer dataset (dset)
        #            ~ @ start: int, list(int), or slice
        #            ~ @ end: np.array with dtype == np.integer
        # shotnum -- int array of global HDF5 shot numbers to be added
        #            to data
        #            ~ data['shotnum'] = shotnum
        #            ~ @ start: int, list(int), or slice
        #            ~ @ end: np.array with dtype == np.integer
        # sni     -- array for mapping index to shotnum
        #            ~ data['shotnum'][sni] = dheader[index, shotnumkey]
        #            ~ data['signal'][sni, ...] = dset[index, ...]
        #            ~ data['singal'][np.logical_not(sni), ...] = np.nan
        #            ~ @ start: not defined
        #            ~ @ end: np.array with dtype == np.bool
        #
        # - Indexing behavior: (depends on intersection_set)
        #
        #   ~ intersection_set is only considered if add_controls
        #     is not None
        #
        #   ~ intersection_set = True (DEFAULT)
        #     * will ensure the returned array will only contain shot
        #       numbers (shotnum) that has data in the digitizer dataset
        #       and all specified control device datasets
        #     * index
        #       > will be the row index of the digitizer dataset
        #       > may be trimmed to enforce shot number intersection of
        #         all datasets
        #     * shotnum
        #       > will be the desired global shot numbers
        #       > may be trimmed to enforce shot number intersection of
        #         all datasets
        #
        #   ~ intersection_set = False
        #     * does not enforce shot number intersection of all
        #       datasets. Instead, if a dataset does not include a
        #       specified shot number, then that entry will be given a
        #       numpy.nan value
        #     * index
        #       > will be the row index of the digitizer dataset
        #     * shotnum
        #       > will be the desired global shot numbers
        #
        # rename 'shots' to 'index'
        if 'shots' in kwargs and index is None:
            index = kwargs['shots']

        # Determine if indexing w.r.t. `index` or `shotnum`
        index_with = 'shotnum' \
            if shotnum != slice(None) and index == slice(None)\
            else 'index'

        # Condition `index` and `shotnum` keywords
        # - Valid indexing types are: int, list(int), and slice()
        #
        if index_with == 'index':
            # Condition `index` keyword
            #
            # Note: I'm letting the slicing of dset[index, shotnumkey]
            #       to throw the appropriate errors
            #
            # Define `shotnum`
            shotnum = dheader[index, shotnumkey].view()
            if shotnum.shape == () and shotnum.size == 1:
                shotnum = np.array([shotnum]).view()

            # define sni
            sni = np.ones(shotnum.shape[0], dtype=bool)

            # convert `index` to np.ndarray
            if type(index) is int:
                index = np.array([index])
            elif type(index) is list:
                index = np.array(index)
            elif type(index) is slice:
                start, stop, step = index.indices(dheader.shape[0])
                index = np.arange(start, stop, step)

            # print execution timing
            if timeit:
                tt.append(time.time())
                print('tt - condition index: '
                      '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))
        else:
            # Condition `shotnum` keyword
            #
            # convert `shotnum` to list
            if isinstance(shotnum, slice):
                # determine largest possible shot number
                last_sn = dheader[-1, shotnumkey]
                if shotnum.stop is not None:
                    stop_sn = max(shotnum.stop, last_sn + 1)
                else:
                    stop_sn = last_sn + 1

                # get the start, stop, and step for the shot number
                # array
                start, stop, step = shotnum.indices(stop_sn)

                # determine smallest possible shot number
                # - intersection_set = True
                #   * start = max of first_sn and shotnum.start
                # - intersection_set = False
                #   * start = min of first_sn and shotnum.start
                first_sn = [dheader[0, shotnumkey]]
                if shotnum.start is not None:
                    # ensure shot numbers are >= 1
                    if start <= 0:
                        start = 1
                else:
                    # start wasn't specified in slice object
                    start = min(first_sn)

                # adjust start for intersection_set
                if intersection_set:
                    first_sn.append(start)
                    start = max(first_sn)

                # re-define shotnum as a list
                shotnum = np.arange(start, stop, step).tolist()
            elif isinstance(shotnum, int):
                shotnum = [shotnum]
            elif isinstance(shotnum, list):
                # ensure all elements are int
                if not all(isinstance(sn, int) for sn in shotnum):
                    raise ValueError('Valid `shotnum` not passed')
            else:
                raise ValueError('Valid `shotnum` not passed')

            # Calc. the corresponding `index` and `sni`
            # - `shotnum` will be converted from list to np.array
            # - `index` and `sni` will be np.array's
            index, shotnum, sni = \
                condition_shotnum(shotnum, dheader, shotnumkey,
                                  intersection_set)

            # print execution timing
            if timeit:
                tt.append(time.time())
                print('tt - condition shotnum: '
                      '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # ---- Retrieve Control Data ---
        # 1. retrieve the numpy array for control data
        # 2. re-filter shotnum if intersection_set=True s.t. only
        #    shotnum's w/ control data are returned
        #
        # grab control device dataset
        #
        # - this will ensure cdata.shape == data.shape all the time
        # - shotnum should always be a ndarray at this point
        #
        if len(controls) != 0:
            cdata = hdfReadControl(hdf_file,
                                   controls,
                                   assume_controls_conditioned=True,
                                   shotnum=shotnum.tolist(),
                                   intersection_set=intersection_set,
                                   silent=silent)

            # print execution timing
            if timeit:
                tt.append(time.time())
                print('tt - read in cdata (control data): '
                      '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

            # re-filter index, shotnum, and sni
            # - only need to be filtered if intersection_set=True
            # - for intersection_set=True, shotnum and index are
            #   one-to-one
            #
            if intersection_set:
                new_sn_mask = np.isin(shotnum, cdata['shotnum'])
                if True not in new_sn_mask:
                    raise ValueError(
                        'Input shotnum would result in a null array')
                else:
                    shotnum = shotnum[new_sn_mask]
                    index = index[new_sn_mask]
                    sni = np.ones(shotnum.shape[0], dtype=bool)
        else:
            cdata = None

        # ---- Construct obj ---
        # - obj will be a numpy record array
        #
        # Define dtype for obj
        # - 1st column of the digi data header contains the global HDF5
        #   file shot number
        # - shotkey = is the field name/key of the dheader shot number
        #   column
        sigtype = '<f4' if not keep_bits else dset.dtype
        shape = shotnum.shape[0]
        dtype = [('shotnum', '<u4'), ('signal', sigtype, dset.shape[1]),
                 ('xyz', '<f4', 3)]
        if len(controls) != 0:
            for subdtype in cdata.dtype.descr:
                if subdtype[0] not in [d[0] for d in dtype]:
                    dtype.append(subdtype)

        # Define numpy array
        data = np.empty(shape, dtype=dtype)

        # print execution timing
        if timeit:
            tt.append(time.time())
            print('tt - define data: '
                  '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # make sure index is not an ndarray
        if type(index) is np.ndarray:
            index = index.tolist()

        # fill 'shotnum' field of data array
        data['shotnum'] = shotnum

        # fill 'signal' fields of data array
        if intersection_set:
            # fill signal
            data['signal'] = dset[index, :]
        else:
            # fill signal
            data['signal'][sni] = dset[index, :]
            if np.issubdtype(data['signal'].dtype, np.integer):
                data['signal'][np.logical_not(sni)] = -99999
            else:
                # dtype is np.floating
                data['signal'][np.logical_not(sni)] = np.nan

        # fill fields related to controls
        if len(controls) != 0:
            # Note: shot numbers of cdata and data are one-to-one
            #       by this point so intersection_set is irrelevant
            #
            if not np.array_equal(data['shotnum'], cdata['shotnum']):
                raise ValueError("data['shotnum'] and cdata['shotnum'] are not"
                                 " equal")

            # fill xyz
            if 'xyz' in cdata.dtype.names:
                data['xyz'] = cdata['xyz']
            else:
                data['xyz'] = np.nan

            # fill remaining controls
            for field in cdata.dtype.names:
                if field not in ['shotnum', 'xyz']:
                    data[field] = cdata[field]
        else:
            # fill xyz
            data['xyz'] = np.nan

        # print execution timing
        if timeit:
            tt.append(time.time())
            print('tt - fill data array: '
                  '{} ms'.format((tt[-1] - tt[-2]) * 1.E3))

        # Define obj to be returned
        obj = data.view(cls)

        # get voltage offset
        try:
            voffset = dheader[0, 'Offset']
        except ValueError:
            voffset = None

        # assign dataset meta-info
        obj._info = {
            'hdf file': hdf_file.filename.split('/')[-1],
            'dataset name': dname,
            'dataset path': dpath,
            'digitizer': d_info['digitizer'],
            'configuration name': d_info['configuration name'],
            'adc': d_info['adc'],
            'bit': d_info['bit'],
            'sample rate': d_info['sample rate'],
            'sample average': d_info['sample average (hardware)'],
            'shot average': d_info['shot average (software)'],
            'board': board,
            'channel': channel,
            'voltage offset': voffset,
            'probe name': None,
            'port': (None, None),
            'signal units': 'bits',
            'added controls': controls
        }

        # plasma parameter dict
        obj._plasma = {
            'Bo': None,
            'kT': None,
            'kTe': None,
            'kTi': None,
            'gamma': core.FloatUnit(1.0, 'arb'),
            'm_e': core.ME,
            'm_i': None,
            'n': None,
            'n_e': None,
            'n_i': None,
            'Z': None
        }

        # convert to voltage
        # - 'signal' dtype is assigned based on keep_bit
        #
        # obj['signal'] = obj['signal'].astype(np.float32, copy=False)
        #
        if not keep_bits:
            # define offset
            offset = abs(obj.info['voltage offset'])

            # calc voltage
            obj['signal'] = (obj.dv * obj['signal']) - offset

            # update 'signal units'
            obj._info['signal units'] = 'V'

        # print warnings
        if not silent and warn_str != '':
            print(warn_str)

        # print execution timing
        if timeit:
            tt.append(time.time())
            print('tt - execution time: '
                  '{} ms'.format((tt[-1] - tt[0]) * 1.E3))

        # return obj
        return obj