def testNxProcess(self): with self.h5open('testNxProcess') as h5group: entry = NexusUtils.nxEntry(h5group, 'entry0001') configdict = ConfigDict.ConfigDict(initdict={'a': 1, 'b': 2}) process = NexusUtils.nxProcess(entry, 'process0001', configdict=configdict) self.assertRaises(RuntimeError, NexusUtils.nxProcess, h5group, 'process0002', configdict=configdict) self.validateNxProcess(process)
def _getNXdataGroup(self, group): """ Get h5py.Group (create when missing, verify class when present) :param str group: """ parent = self._nxprocess['results'] if group in parent: nxdata = parent[group] NexusUtils.raiseIsNotNxClass(nxdata, u'NXdata') else: nxdata = NexusUtils.nxData(parent, group) return nxdata
def _saveImages(self): from PyMca5.PyMca import ArraySave # List of images in deterministic order imageFileLabels, imageTitleLabels, imageList = self._imageList() if not imageFileLabels: return NexusUtils.mkdir(self.outroot_localfs) if self.edf: if self.multipage: fileName = self.filename('.edf') self._checkOverwrite(fileName) ArraySave.save2DArrayListAsEDF(imageList, fileName, labels=imageTitleLabels) else: for label, title, image in zip(imageFileLabels, imageTitleLabels, imageList): fileName = self.filename('.edf', suffix="_" + label) self._checkOverwrite(fileName) ArraySave.save2DArrayListAsEDF([image], fileName, labels=[title]) if self.tif: if self.multipage: fileName = self.filename('.tif') self._checkOverwrite(fileName) ArraySave.save2DArrayListAsMonochromaticTiff(imageList, fileName, labels=imageTitleLabels, dtype=numpy.float32) else: for label, title, image in zip(imageFileLabels, imageTitleLabels, imageList): fileName = self.filename('.tif', suffix="_" + label) self._checkOverwrite(fileName) ArraySave.save2DArrayListAsMonochromaticTiff([image], fileName, labels=[title], dtype=numpy.float32) if self.csv: fileName = self.filename('.csv') self._checkOverwrite(fileName) ArraySave.save2DArrayListAsASCII(imageList, fileName, csv=True, labels=imageTitleLabels) if self.dat: fileName = self.filename('.dat') self._checkOverwrite(fileName) ArraySave.save2DArrayListAsASCII(imageList, fileName, csv=False, labels=imageTitleLabels) if self.cfg and self._configurationkey in self: fileName = self.filename('.cfg') self._checkOverwrite(fileName) self[self._configurationkey].write(fileName)
def _readImageListHdf5(self, filenamelist): if h5py is None: self._criticalError("Cannot read HDF5 files (h5py is missing)") return None, None imagelist = [] imagenames = [] shape = tuple(sorted(self._requiredShape)) def match(dset): return tuple(sorted(dset.shape)) == shape for uri in filenamelist: tmp = uri.split('::') if len(tmp) == 1: tmp = uri, None filename, h5path = tmp # URI exists? if h5path: with HDF5Widget.h5open(filename) as hdf5File: if h5path not in hdf5File: h5path = None # Prompt for missing HDF5 path if not h5path: tmp = HDF5Widget.getUri(parent=self._dialogParent, filename=filename, message='Select Group or Dataset') if not tmp: return None, None tmp = tmp.split('::') if len(tmp) == 2: h5path = tmp[1] if not h5path: return None, None # Add datasets from HDF5 path with HDF5Widget.h5open(filename) as hdf5File: # If `h5path` is an instance of NXdata, only the signals # (including auxilary signals) are considered for `match`. datasets = NexusUtils.selectDatasets(hdf5File[h5path], match=match) if not datasets: self._criticalError( "No (valid) datasets were found in '%s::%s'" % (filename, h5path)) return None, None elif len({dset.size for dset in datasets}) > 1: self._criticalError( "'%s::%s' contains datasets with different sizes. Select datasets separately." % (filename, h5path)) return None, None else: for dset in datasets: imagename = '/'.join(dset.name.split('/')[-2:]) imagelist.append(dset[()]) imagenames.append(imagename) if not imagenames: self._criticalError('No valid data provided') return imagenames, imagelist
def _saveSingle(self): from PyMca5.PyMca import ArraySave imageNames = [] imageList = [] lst = [('parameter_names', 'parameters', '{}'), ('parameter_names', 'uncertainties', 's({})'), ('massfraction_names', 'massfractions', 'w({}){}')] for names, key, fmt in lst: images = self.get(key, None) if images is not None: for img in images: imageList.append(img) imageNames += self._getNames(names, fmt) NexusUtils.mkdir(self.outroot_localfs) if self.edf: fileName = self.filename('.edf') self._checkOverwrite(fileName) ArraySave.save2DArrayListAsEDF(imageList, fileName, labels=imageNames) if self.csv: fileName = self.filename('.csv') self._checkOverwrite(fileName) ArraySave.save2DArrayListAsASCII(imageList, fileName, csv=True, labels=imageNames) if self.tif: for label, image in zip(imageNames, imageList): if label.startswith("s("): suffix = "_s" + label[2:-1] elif label.startswith("w("): suffix = "_w" + label[2:-1] else: suffix = "_" + label fileName = self.filename('.tif', suffix=suffix) self._checkOverwrite(fileName) ArraySave.save2DArrayListAsMonochromaticTiff( [image], fileName, labels=[label], dtype=numpy.float32) if self.cfg and 'configuration' in self: fileName = self.filename('.cfg') self._checkOverwrite(fileName) self['configuration'].write(fileName)
def _saveSingle(self): from PyMca5.PyMca import ArraySave imageNames = [] imageList = [] lst = [('parameter_names', 'parameters', '{}'), ('parameter_names', 'uncertainties', 's({})'), ('massfraction_names', 'massfractions', 'w({}){}')] for names, key, fmt in lst: images = self.get(key, None) if images is not None: for img in images: imageList.append(img) imageNames += self._getNames(names, fmt) NexusUtils.mkdir(self.outroot_localfs) if self.edf: fileName = self.filename('.edf') self._checkOverwrite(fileName) ArraySave.save2DArrayListAsEDF(imageList, fileName, labels=imageNames) if self.csv: fileName = self.filename('.csv') self._checkOverwrite(fileName) ArraySave.save2DArrayListAsASCII(imageList, fileName, csv=True, labels=imageNames) if self.tif: for label,image in zip(imageNames, imageList): if label.startswith("s("): suffix = "_s" + label[2:-1] elif label.startswith("w("): suffix = "_w" + label[2:-1] else: suffix = "_" + label fileName = self.filename('.tif', suffix=suffix) self._checkOverwrite(fileName) ArraySave.save2DArrayListAsMonochromaticTiff([image], fileName, labels=[label], dtype=numpy.float32) if self.cfg and 'configuration' in self: fileName = self.filename('.cfg') self._checkOverwrite(fileName) self['configuration'].write(fileName)
def _h5Context(self, cleanup_funcs, update=True): """ Initialize NXprocess on enter and close/cleanup on exit """ if self.nosave: yield else: fileName = self.filename('.h5') existed = [False]*3 # h5file, nxentry, nxprocess existed[0] = os.path.exists(fileName) with NexusUtils.nxRoot(fileName, mode='a') as f: # Open/overwrite NXprocess: h5file::/entry/process entryname = self.fileEntry existed[1] = entryname in f entry = NexusUtils.nxEntry(f, entryname) procname = self.fileProcess if procname in entry: existed[2] = True path = entry[procname].name if update: _logger.debug('edit {}'.format(path)) elif self.overwrite: _logger.info('overwriting {}::{}'.format(fileName, path)) del entry[procname] existed[2] = False else: raise RuntimeError('{}::{} already exists'.format(fileName, path)) self._nxprocess = NexusUtils.nxProcess(entry, procname) try: with self._h5DatasetContext(f): yield except: # clean-up and re-raise if not existed[0]: cleanup_funcs.append(lambda: os.remove(fileName)) elif not existed[1]: del f[entryname] elif not existed[2]: del entry[procname] raise finally: self._nxprocess = None
def exportStackList(stackList, filename, channels=None, calibration=None): if hasattr(stackList, "data") and hasattr(stackList, "info"): stackList = [stackList] if isinstance(filename, h5py.File): h5 = filename _exportStackList(stackList, h5, channels=channels, calibration=calibration) else: h5 = h5py.File(filename, "w-") try: if HAS_NEXUS_UTILS: NexusUtils.nxRootInit(h5) _exportStackList(stackList, h5, channels=channels, calibration=calibration) finally: h5.close()
def _h5Context(self, cleanup_funcs, update=True): """ Initialize NXprocess on enter and close/cleanup on exit """ fileName = self.filename('.h5') existed = [False] * 3 existed[0] = os.path.exists(fileName) with NexusUtils.nxRoot(fileName, mode='a') as f: # Open/overwrite NXprocess: root/entry/process entryname = self.fileEntry existed[1] = entryname in f entry = NexusUtils.nxEntry(f, entryname) procname = self.fileProcess if procname in entry: existed[2] = True path = entry[procname].name if update: _logger.debug('edit {}'.format(path)) elif self.overwrite: _logger.warning('overwriting {}'.format(path)) del entry[procname] existed[2] = False else: raise RuntimeError('{} already exists'.format(path)) self._nxprocess = NexusUtils.nxProcess(entry, procname) try: with self._h5DatasetContext(f): yield except: # clean-up and re-raise if not existed[0]: cleanup_funcs.append(lambda: os.remove(fileName)) elif not existed[1]: del f[entryname] elif not existed[2]: del entry[procname] raise finally: self._nxprocess = None
def allocateH5(self, name, nxdata=None, fill_value=None, **kwargs): """ :param str name: :param str nxdata: :param num fill_value: :param \**kwargs: see h5py.Group.create_dataset """ parent = self._nxprocess['results'] if nxdata: parent = NexusUtils.nxData(parent, nxdata) buffer = parent.create_dataset(name, **kwargs) if fill_value is not None: buffer[()] = fill_value self.flush() self._output[name] = buffer return buffer
def generateHdf5Map(filename, **kwargs): """ :param str filename: save data under this name :param **kwargs: see `generate` :returns dict: {filelist: list(str), configuration: ConfigDict, data: ndarray(nDet, nRows, nColumns, nChannels), liveTime: ndarray(nDet, nRows, nColumns), presetTime: number} """ from PyMca5.PyMcaIO import NexusUtils info = generate(**kwargs) preset_time = info['configuration']["concentrations"]["time"] basename = os.path.splitext(os.path.basename(filename))[0] path = os.path.dirname(filename) cfgname = os.path.join(path, basename+'.cfg') with NexusUtils.nxRoot(filename, mode='w') as f: entry = NexusUtils.nxEntry(f, basename) instrument = NexusUtils.nxInstrument(entry) xrf = NexusUtils.nxSubEntry(entry, 'xrf') for iDet, (detData, detLT) in enumerate(zip(info['data'], info['liveTime'])): name = 'mca{:02}'.format(iDet) detector = NexusUtils.nxDetector(instrument, name) detector['data'] = detData detector['data'].attrs['interpretation'] = 'spectrum' xdetector = NexusUtils.nxCollection(xrf, name) xdetector['data'] = NexusUtils.h5py.SoftLink(detector['data'].name) xdetector['preset_time'] = preset_time xdetector['live_time'] = detLT xdetector['live_time'].attrs['interpretation'] = 'image' xdetector['live_time'].attrs['units'] = 's' #nxprocess = NexusUtils.nxProcess(entry, 'fit') #NexusUtils.nxProcessConfigurationInit(nxprocess, configdict=info['configuration']) info['configuration'].write(cfgname) info['filelist'] = [filename] return info
def h5open(self, name): filename = os.path.join(self.path, name+'.h5') with NexusUtils.nxRoot(filename, mode='a') as h5group: yield h5group
def _checkStringTypes(self, attribute=True, raiseExtended=True): # Test following string literals sAsciiBytes = b'abc' sAsciiUnicode = u'abc' sLatinBytes = b'\xe423' sLatinUnicode = u'\xe423' # not used sUTF8Unicode = u'\u0101bc' sUTF8Bytes = b'\xc4\x81bc' sUTF8AsciiUnicode = u'abc' sUTF8AsciiBytes = b'abc' # Expected conversion after HDF5 write/read strmap = {} strmap['ascii(scalar)'] = sAsciiBytes,\ sAsciiUnicode strmap['ext(scalar)'] = sLatinBytes,\ sLatinBytes strmap['unicode(scalar)'] = sUTF8Unicode,\ sUTF8Unicode strmap['unicode2(scalar)'] = sUTF8AsciiUnicode,\ sUTF8AsciiUnicode strmap['ascii(list)'] = [sAsciiBytes, sAsciiBytes],\ [sAsciiUnicode, sAsciiUnicode] strmap['ext(list)'] = [sLatinBytes, sLatinBytes],\ [sLatinBytes, sLatinBytes] strmap['unicode(list)'] = [sUTF8Unicode, sUTF8Unicode],\ [sUTF8Unicode, sUTF8Unicode] strmap['unicode2(list)'] = [sUTF8AsciiUnicode, sUTF8AsciiUnicode],\ [sUTF8AsciiUnicode, sUTF8AsciiUnicode] strmap['mixed(list)'] = [sUTF8Unicode, sUTF8AsciiUnicode, sAsciiBytes, sLatinBytes],\ [sUTF8Bytes, sUTF8AsciiBytes, sAsciiBytes, sLatinBytes] strmap['ascii(0d-array)'] = numpy.array(sAsciiBytes),\ sAsciiUnicode strmap['ext(0d-array)'] = numpy.array(sLatinBytes),\ sLatinBytes strmap['unicode(0d-array)'] = numpy.array(sUTF8Unicode),\ sUTF8Unicode strmap['unicode2(0d-array)'] = numpy.array(sUTF8AsciiUnicode),\ sUTF8AsciiUnicode strmap['ascii(1d-array)'] = numpy.array([sAsciiBytes, sAsciiBytes]),\ [sAsciiUnicode, sAsciiUnicode] strmap['ext(1d-array)'] = numpy.array([sLatinBytes, sLatinBytes]),\ [sLatinBytes, sLatinBytes] strmap['unicode(1d-array)'] = numpy.array([sUTF8Unicode, sUTF8Unicode]),\ [sUTF8Unicode, sUTF8Unicode] strmap['unicode2(1d-array)'] = numpy.array([sUTF8AsciiUnicode, sUTF8AsciiUnicode]),\ [sUTF8AsciiUnicode, sUTF8AsciiUnicode] strmap['mixed(1d-array)'] = numpy.array([sUTF8Unicode, sUTF8AsciiUnicode, sAsciiBytes]),\ [sUTF8Unicode, sUTF8AsciiUnicode, sAsciiUnicode] strmap['mixed2(1d-array)'] = numpy.array([sUTF8AsciiUnicode, sAsciiBytes]),\ [sUTF8AsciiUnicode, sAsciiUnicode] with self.h5open('testNxString{:d}'.format(attribute)) as h5group: h5group = h5group.create_group('test') if attribute: out = h5group.attrs else: out = h5group for name, (value, expectedValue) in strmap.items(): decodingError = 'ext' in name or name == 'mixed(list)' if raiseExtended and decodingError: with self.assertRaises(UnicodeDecodeError): ovalue = NexusUtils.asNxChar(value, raiseExtended=raiseExtended) continue else: ovalue = NexusUtils.asNxChar(value, raiseExtended=raiseExtended) # Write/read out[name] = ovalue if attribute: value = out[name] else: value = out[name][()] # Expected type and value? if 'list' in name or '1d-array' in name: self.assertTrue(isinstance(value, numpy.ndarray)) value = value.tolist() self.assertEqual(list(map(type, value)), list(map(type, expectedValue)), msg=name) firstValue = value[0] else: firstValue = value msg = '{} {} instead of {}'.format(name, type(value), type(expectedValue)) self.assertEqual(type(value), type(expectedValue), msg=msg) self.assertEqual(value, expectedValue, msg=name) # Expected character set? if not attribute: charSet = out[name].id.get_type().get_cset() if isinstance(firstValue, bytes): # This is the tricky part, CSET_ASCII is supposed to be only 0-127 # while we actually allow expectedCharSet = h5py.h5t.CSET_ASCII else: expectedCharSet = h5py.h5t.CSET_UTF8 msg = '{} type {} instead of {}'.format(name, charSet, expectedCharSet) self.assertEqual(charSet, expectedCharSet, msg=msg)
def testNxData(self): with self.h5open('testNxEntry') as h5group: entry = NexusUtils.nxEntry(h5group, 'entry0001') process = NexusUtils.nxProcess(entry, 'process0001') data = NexusUtils.nxData(process['results'], 'data') s = (4, 3, 2) axes = [('y', numpy.arange(s[0]), {'units': 'um'}), ('x', numpy.arange(s[1]), {}), ('z', {'shape': (s[2],), 'dtype': int}, None)] signals = [('Fe K', numpy.zeros(s), {'interpretation': 'image'}), ('Ca K', {'data': numpy.zeros(s)}, {}), ('S K', {'shape': s, 'dtype': int}, None)] NexusUtils.nxDataAddAxes(data, axes) NexusUtils.nxDataAddSignals(data, signals) self.validateNxData(data, axes, signals) signals = NexusUtils.nxDataGetSignals(data) self.assertEqual(signals, ['Fe K', 'Ca K', 'S K']) NexusUtils.markDefault(data['Ca K']) data = entry[NexusUtils.DEFAULT_PLOT_NAME] signals = NexusUtils.nxDataGetSignals(data) self.assertEqual(signals, ['Ca K', 'Fe K', 'S K']) self.assertEqual(data['y'].attrs['units'], 'um') self.assertEqual(data['Fe K'].attrs['interpretation'], 'image') for name in signals: self.assertEqual(data[name].shape, s) for n, name in zip(s, list(next(iter(zip(*axes))))): self.assertEqual(data[name].shape, (n,))
def _saveH5(self): # Save fit configuration nxprocess = self._nxprocess if nxprocess is None: return nxresults = nxprocess['results'] configdict = self.get('configuration', None) NexusUtils.nxProcessConfigurationInit(nxprocess, configdict=configdict) # Save fitted parameters, uncertainties and elemental massfractions mill = numpy.float32(1e6) lst = [('parameter_names', 'uncertainties'), ('parameter_names', 'parameters'), ('massfraction_names', 'massfractions')] for names, key in lst: images = self.get(key, None) if images is not None: attrs = {'interpretation': 'image'} signals = [(label, {'data': img, 'chunks': True}, attrs) for label, img in zip(self[names], images)] data = NexusUtils.nxData(nxresults, key) NexusUtils.nxDataAddSignals(data, signals) NexusUtils.markDefault(data) if 'parameters' in nxresults and 'uncertainties' in nxresults: NexusUtils.nxDataAddErrors(nxresults['parameters'], nxresults['uncertainties']) # Save fitted model and residuals signals = [] attrs = {'interpretation': 'spectrum'} for name in ['data', 'model', 'residuals']: if name in self: signals.append((name, self[name], attrs)) if signals: nxdata = NexusUtils.nxData(nxresults, 'fit') NexusUtils.nxDataAddSignals(nxdata, signals) axes = self.get('dataAxes', None) axes_used = self.get('dataAxesUsed', None) if axes: NexusUtils.nxDataAddAxes(nxdata, axes) if axes_used: axes = [(ax, None, None) for ax in axes_used] NexusUtils.nxDataAddAxes(nxdata, axes, append=False) # Save diagnostics signals = [] attrs = {'interpretation':'image'} for name in ['nObservations', 'nFreeParameters']: img = self.get(name, None) if img is not None: signals.append((name, img, attrs)) if signals: nxdata = NexusUtils.nxData(nxresults, 'diagnostics') NexusUtils.nxDataAddSignals(nxdata, signals)
def testNxEntry(self): with self.h5open('testNxEntry') as h5group: entry = NexusUtils.nxEntry(h5group, 'entry0001') self.assertRaises(RuntimeError, NexusUtils.nxEntry, entry, 'entry0002') self.validateNxEntry(entry)
def _exportStackList(stackList, h5, path=None, channels=None, calibration=None): if path is None: # initialize the entry entryName = "stack" else: entryName = path if entryName not in h5 and HAS_NEXUS_UTILS: NexusUtils.nxEntryInit(h5, entryName) entry = h5.require_group(entryName) att = "NX_class" if att not in entry.attrs: entry.attrs[att] = u"NXentry" instrumentName = "instrument" instrument = entry.require_group(instrumentName) if att not in instrument.attrs: instrument.attrs[att] = u"NXinstrument" # save all the stacks dataTargets = [] i = 0 for stack in stackList: detectorName = "detector_%02d" % i detector = instrument.require_group(detectorName) if att not in detector.attrs: detector.attrs[att] = u"NXdetector" detectorPath = posixpath.join("/", entryName, instrumentName, detectorName) exportStack(stack, h5, detectorPath, channels=channels, calibration=calibration) dataPath = posixpath.join(detectorPath, "data") dataTargets.append(dataPath) i += 1 # create NXdata measurement = entry.require_group("measurement") if att not in measurement.attrs: measurement.attrs[att] = u"NXdata" att = "default" if att not in entry.attrs: entry.attrs[att] = u"measurement" i = 0 auxiliary = [] for target in dataTargets: name = posixpath.basename(posixpath.dirname(target)) measurement[name] = h5py.SoftLink(target) if i == 0: measurement.attrs["signal"] = name else: auxiliary.append(name) if len(auxiliary): measurement.attrs["auxiliary_signals"] = numpy.array(auxiliary, dtype=strdtype) h5.flush() return entryName
def _saveH5(self): # Save fit configuration nxprocess = self._nxprocess if nxprocess is None: return nxresults = nxprocess['results'] configdict = self.get('configuration', None) NexusUtils.nxProcessConfigurationInit(nxprocess, configdict=configdict) # Save fitted parameters, uncertainties and elemental massfractions mill = numpy.float32(1e6) lst = [('parameter_names', 'uncertainties'), ('parameter_names', 'parameters'), ('massfraction_names', 'massfractions')] for names, key in lst: images = self.get(key, None) if images is not None: attrs = {'interpretation': 'image'} signals = [(label, { 'data': img, 'chunks': True }, attrs) for label, img in zip(self[names], images)] data = NexusUtils.nxData(nxresults, key) NexusUtils.nxDataAddSignals(data, signals) NexusUtils.markDefault(data) if 'parameters' in nxresults and 'uncertainties' in nxresults: NexusUtils.nxDataAddErrors(nxresults['parameters'], nxresults['uncertainties']) # Save fitted model and residuals signals = [] attrs = {'interpretation': 'spectrum'} for name in ['data', 'model', 'residuals']: if name in self: signals.append((name, self[name], attrs)) if signals: nxdata = NexusUtils.nxData(nxresults, 'fit') NexusUtils.nxDataAddSignals(nxdata, signals) axes = self.get('dataAxes', None) axes_used = self.get('dataAxesUsed', None) if axes: NexusUtils.nxDataAddAxes(nxdata, axes) if axes_used: axes = [(ax, None, None) for ax in axes_used] NexusUtils.nxDataAddAxes(nxdata, axes, append=False) # Save diagnostics signals = [] attrs = {'interpretation': 'image'} for name in ['nObservations', 'nFreeParameters']: img = self.get(name, None) if img is not None: signals.append((name, img, attrs)) if signals: nxdata = NexusUtils.nxData(nxresults, 'diagnostics') NexusUtils.nxDataAddSignals(nxdata, signals)
def _saveH5(self): nxprocess = self._nxprocess if nxprocess is None: return # Save fit configuration configdict = self.get(self._configurationkey, None) NexusUtils.nxProcessConfigurationInit(nxprocess, configdict=configdict) # Save allocated memory nxresults = nxprocess['results'] adderrors = [] markdefault = [] for group, info in self._results.items(): # Create group nxdata = self._getNXdataGroup(group) # Add signals NexusUtils.nxDataAddSignals(nxdata, info['_signals']) # Add axes axes = info.get('axes', None) axes_used = info.get('axesused', None) if axes: NexusUtils.nxDataAddAxes(nxdata, axes) if axes_used: axes = [(ax, None, None) for ax in axes_used] NexusUtils.nxDataAddAxes(nxdata, axes, append=False) # Add error links errors = info['errors'] if errors: adderrors.append((nxdata, errors)) # Default nxdata for visualization if info['default']: markdefault.append(nxdata) # Error links and default for visualization for nxdata, errors in adderrors: if errors in nxresults: NexusUtils.nxDataAddErrors(nxdata, nxresults[errors]) if markdefault: NexusUtils.markDefault(markdefault[-1]) else: for group in self._defaultgroups: if group in nxresults: NexusUtils.markDefault(nxresults[group]) break