コード例 #1
0
 def writer(self, h5parent, writer, scan, nxclass=None, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     # consider putting this info under NXsample or NXentry/metadata
     if hasattr(scan, 'TEMP_SP'):
         write_dataset(h5parent, "TEMP_SP", scan.TEMP_SP, description='temperature set point')
     if hasattr(scan, 'DEGC_SP'):
         write_dataset(h5parent, "DEGC_SP", scan.DEGC_SP, units='C', description='temperature set point (C)')
コード例 #2
0
ファイル: test_eznx.py プロジェクト: JPHammonds/spec2nexus
    def test_makeExternalLink(self):
        external = eznx.makeFile('external.h5', creator='eznx', default='entry')
        eznx.write_dataset(external, "text", "some text")

        root = eznx.makeFile('test.h5', creator='eznx', default='entry')
        nxentry = eznx.makeGroup(root, 'entry', 'NXentry', default='data')
        eznx.makeExternalLink(root, 'external.h5', "/text", nxentry.name + "/external_text")

        # check the external file first
        with h5py.File("external.h5", "r") as hp:
            root = hp["/"]
            self.assertTrue("text" in root)
            ds = root["text"]
            value = ds[()]        # ds.value deprecated in h5py
            self.assertEqual(value, [b"some text"])

        # check the file with the external link
        with h5py.File("test.h5", "r") as hp:
            root = hp["/"]
            nxentry = root["entry"]
            self.assertTrue("external_text" in nxentry)
            value = eznx.read_nexus_field(nxentry, "external_text")
            self.assertEqual(value, b"some text")
            value = eznx.read_nexus_field(nxentry, "external_text", astype=str)
            self.assertEqual(value, "some text")
コード例 #3
0
 def writer(self, h5parent, writer, scan, nxclass=None, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     if hasattr(scan, 'MCA'):
         mca_group = openGroup(h5parent, 'MCA', nxclass, description='MCA metadata')
         mca = scan.MCA
         for key in ('number_saved  first_saved  last_saved  reduction_coef'.split()):
             if key in mca:
                 write_dataset(mca_group, key, mca[key])
コード例 #4
0
 def writer(self, h5parent, writer, scan, nxclass=None, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     if hasattr(scan, 'MCA'):
         mca_group = openGroup(h5parent, 'MCA', nxclass, description='MCA metadata')
         mca = scan.MCA
         for key in ('preset_time  elapsed_live_time  elapsed_real_time'.split()):
             if key in mca:
                 write_dataset(mca_group, key, mca[key], units='s')
コード例 #5
0
 def writer(self, h5parent, writer, scan, nxclass=None, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     if hasattr(scan, 'MCA'):
         if 'CALIB' in scan.MCA:
             mca_group = openGroup(h5parent, 'MCA', nxclass, description='MCA metadata')
             calib_dict = scan.MCA['CALIB']
             for key in ('a b c'.split()):
                 if key in calib_dict:
                     write_dataset(mca_group, 'calib_' + key, calib_dict[key])
コード例 #6
0
 def writer(self, h5parent, writer, scan, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     desc = 'SPEC scan with constant counting time'
     write_dataset(h5parent, "counting_basis", desc)
     write_dataset(h5parent,
                   "T",
                   float(scan.T),
                   units='s',
                   description=desc)
コード例 #7
0
 def writer(self, h5parent, writer, scan, nxclass=None, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     if hasattr(scan, 'MCA'):
         if hasattr(scan.MCA, 'ROI'):
             mca_group = openGroup(h5parent, 'MCA', nxclass, description='MCA metadata')
             roi_group = openGroup(mca_group, 'ROI', nxclass, description='Regions Of Interest')
             roi_dict = scan.MCA['ROI']
             for key, roi in roi_dict.items():
                 dataset = [roi['first_chan'], roi['last_chan']]
                 desc = 'first_chan, last_chan'
                 write_dataset(roi_group, key, dataset, description=desc, units='channel')
コード例 #8
0
ファイル: test_eznx.py プロジェクト: JPHammonds/spec2nexus
    def test_write_dataset_existing(self):
        root = eznx.makeFile('test.h5', creator='eznx', default='entry')
        nxentry = eznx.makeGroup(root, 'entry', 'NXentry', default='data')
        eznx.write_dataset(nxentry, "text", "some text")
        eznx.write_dataset(nxentry, "text", "replacement text")

        with h5py.File("test.h5", "r") as hp:
            root = hp["/"]
            nxentry = root["entry"]
            self.assertTrue("text" in nxentry)
            value = eznx.read_nexus_field(nxentry, "text", astype=str)
            self.assertEqual(value, "replacement text")
コード例 #9
0
 def writer(self, h5parent, writer, scan, nxclass=None, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     if hasattr(scan, 'MCA'):
         mca_group = openGroup(h5parent,
                               'MCA',
                               nxclass,
                               description='MCA metadata')
         mca = scan.MCA
         for key in ('preset_time  elapsed_live_time  elapsed_real_time'.
                     split()):
             if key in mca:
                 write_dataset(mca_group, key, mca[key], units='s')
コード例 #10
0
 def writer(self, h5parent, writer, scan, nxclass=None, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     if hasattr(scan, 'MCA'):
         mca_group = openGroup(h5parent,
                               'MCA',
                               nxclass,
                               description='MCA metadata')
         mca = scan.MCA
         for key in ('number_saved  first_saved  last_saved  reduction_coef'
                     .split()):
             if key in mca:
                 write_dataset(mca_group, key, mca[key])
コード例 #11
0
 def writer(self, h5parent, writer, header, nxclass=None, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     if not hasattr(header, 'positioner_xref'):
         header.counter_xref = {}          # mnemonic:name
     desc = 'cross-reference SPEC positioner mnemonics and names'
     comment = 'keys are SPEC positioner mnemonics, values are SPEC positioner names'
     if nxclass is None:
         nxclass = CONTAINER_CLASS
     group = makeGroup(h5parent, "positioner_cross_reference", nxclass, 
                       description=desc, comment=comment)
     for key, value in sorted(header.positioner_xref.items()):
         write_dataset(group, key, value)
コード例 #12
0
 def writer(self, h5parent, writer, scan, nxclass=None, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     if hasattr(scan, 'MCA'):
         if 'CALIB' in scan.MCA:
             mca_group = openGroup(h5parent,
                                   'MCA',
                                   nxclass,
                                   description='MCA metadata')
             calib_dict = scan.MCA['CALIB']
             for key in ('a b c'.split()):
                 if key in calib_dict:
                     write_dataset(mca_group, 'calib_' + key,
                                   calib_dict[key])
コード例 #13
0
 def writer(self, h5parent, writer, scan, nxclass=None, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     # consider putting this info under NXsample or NXentry/metadata
     if hasattr(scan, 'TEMP_SP'):
         write_dataset(h5parent,
                       "TEMP_SP",
                       scan.TEMP_SP,
                       description='temperature set point')
     if hasattr(scan, 'DEGC_SP'):
         write_dataset(h5parent,
                       "DEGC_SP",
                       scan.DEGC_SP,
                       units='C',
                       description='temperature set point (C)')
コード例 #14
0
 def writer(self, h5parent, writer, header, nxclass=None, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     if not hasattr(header, 'positioner_xref'):
         header.counter_xref = {}  # mnemonic:name
     desc = 'cross-reference SPEC positioner mnemonics and names'
     comment = 'keys are SPEC positioner mnemonics, values are SPEC positioner names'
     if nxclass is None:
         nxclass = CONTAINER_CLASS
     group = makeGroup(h5parent,
                       "positioner_cross_reference",
                       nxclass,
                       description=desc,
                       comment=comment)
     for key, value in sorted(header.positioner_xref.items()):
         write_dataset(group, key, value)
コード例 #15
0
 def writer(self, h5parent, writer, scan, nxclass=None, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     if hasattr(scan, 'MCA'):
         if hasattr(scan.MCA, 'ROI'):
             mca_group = openGroup(h5parent,
                                   'MCA',
                                   nxclass,
                                   description='MCA metadata')
             roi_group = openGroup(mca_group,
                                   'ROI',
                                   nxclass,
                                   description='Regions Of Interest')
             roi_dict = scan.MCA['ROI']
             for key, roi in roi_dict.items():
                 dataset = [roi['first_chan'], roi['last_chan']]
                 desc = 'first_chan, last_chan'
                 write_dataset(roi_group,
                               key,
                               dataset,
                               description=desc,
                               units='channel')
コード例 #16
0
ファイル: test_eznx.py プロジェクト: JPHammonds/spec2nexus
    def test_read_nexus_field_alternatives(self):
        root = eznx.makeFile('test.h5', creator='eznx', default='entry')
        nxentry = eznx.makeGroup(root, 'entry', 'NXentry', default='data')
        eznx.write_dataset(nxentry, "text", "some text")
        eznx.write_dataset(nxentry, "number", 42)
        eznx.write_dataset(nxentry, "array", [[1,2,3], [4,5,6]])

        # check the file with the external link
        with h5py.File("test.h5", "r") as hp:
            root = hp["/"]
            nxentry = root["entry"]
            
            value = eznx.read_nexus_field(nxentry, "key_error")
            self.assertEqual(value, None)
            
            value = eznx.read_nexus_field(nxentry, "text")
            self.assertEqual(value, b"some text")
            value = eznx.read_nexus_field(nxentry, "text", astype=str)
            self.assertEqual(value, "some text")
            
            value = eznx.read_nexus_field(nxentry, "number")
            self.assertEqual(value, 42)
            value = eznx.read_nexus_field(nxentry, "number", astype=float)
            self.assertEqual(value, 42)
            value = eznx.read_nexus_field(nxentry, "number", astype=str)
            self.assertEqual(value, "42")
            
            ds = nxentry["array"]
            value = ds[()]        # ds.value deprecated in h5py
            expected = numpy.array([[1,2,3], [4,5,6]])
            self.assertTrue((value == expected).any())

            with self.assertRaises(RuntimeError) as context:
                value = eznx.read_nexus_field(nxentry, "array")
            received = str(context.exception)
            expected = "unexpected 2-D data"
            self.assertTrue(received.startswith(expected))
コード例 #17
0
 def writer(self, h5parent, writer, scan, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     desc = 'SPEC scan with constant counting time'
     write_dataset(h5parent, "counting_basis", desc)
     write_dataset(h5parent, "T", float(scan.T), units='s', description = desc)
コード例 #18
0
 def writer(self, h5parent, writer, scan, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     desc = 'hkl at start of scan'
     write_dataset(h5parent, "Q", scan.Q, description = desc)
コード例 #19
0
 def writer(self, h5parent, writer, scan, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     desc = 'hkl at start of scan'
     write_dataset(h5parent, "Q", scan.Q, description=desc)
コード例 #20
0
 def writer(self, h5parent, writer, scan, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     write_dataset(h5parent, "comments", '\n'.join(map(str, scan.comments)))
コード例 #21
0
 def writer(self, h5parent, writer, scan, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     write_dataset(h5parent, "date", iso8601(scan.date)  )
コード例 #22
0
 def writer(self, h5parent, writer, scan, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     write_dataset(h5parent, "date", iso8601(scan.date))
コード例 #23
0
root = eznx.makeFile(TARGET_FILE, default='entry')
nxentry = eznx.makeGroup(root, 'entry', 'NXentry', default='data')
nxdata = eznx.makeGroup(nxentry, 'data', 'NXdata', signal='frames', )
nxinstrument = eznx.makeGroup(nxentry, 'instrument', 'NXinstrument')
nxdetector = eznx.makeGroup(nxinstrument, 'detector', 'NXdetector')
nxsource = eznx.makeGroup(nxinstrument, 'source', 'NXsource')
nxmonochromator = eznx.makeGroup(nxinstrument, 'monochromator', 'NXmonochromator')
nxcollimator = eznx.makeGroup(nxinstrument, 'collimator', 'NXcollimator')
nxgeometry_slit = eznx.makeGroup(nxcollimator, 'geometry', 'NXgeometry')
nxshape_slit = eznx.makeGroup(nxgeometry_slit, 'shape', 'NXshape')
nxsample = eznx.makeGroup(nxinstrument, 'sample', 'NXsample')
nxmonitor = eznx.makeGroup(nxinstrument, 'control', 'NXmonitor')

# various metadata
eznx.addAttributes(root, creator=h5.attrs['creator'] + ' and spec2nexus.eznx')
eznx.write_dataset(nxentry, 'title', 'NeXus NXsas example')
eznx.write_dataset(nxentry, 'definition', 'NXsas', URL='http://download.nexusformat.org/doc/html/classes/applications/NXsas.html')
eznx.write_dataset(nxentry, 'start_time', h5_files[0].attrs['file_time'])
eznx.write_dataset(nxentry, 'end_time', h5_files[-1].attrs['file_time'])
eznx.write_dataset(nxdetector, 'frame_files', '\n'.join(names))
eznx.write_dataset(nxinstrument, 'name', 'APS 9-ID-C USAXS pinSAXS')
eznx.write_dataset(nxsource, 'type', 'Synchrotron X-ray Source')
eznx.write_dataset(nxsource, 'name', 'Advanced Photon Source Undulator A, sector 9ID-C')
eznx.write_dataset(nxsource, 'probe', 'x-ray')
eznx.write_dataset(nxsource, 'current', h5['/entry/EPICS_PV_metadata/SRcurrent'], units='mA')
eznx.write_dataset(nxsource, 'energy', float(7), units='GeV')
eznx.write_dataset(nxmonochromator, 'energy', h5['/entry/instrument/monochromator/energy'], units='keV')
eznx.write_dataset(nxmonochromator, 'wavelength', h5['/entry/EPICS_PV_metadata/wavelength'], units='Angstroms')
eznx.write_dataset(nxmonochromator, 'wavelength_spread', h5['/entry/EPICS_PV_metadata/wavelength_spread'], units='Angstroms/Angstroms')
eznx.write_dataset(nxshape_slit, 'shape', 'nxbox')
# next four are not defined in the NXsas specification
コード例 #24
0
 def writer(self, h5parent, writer, scan, *args, **kws):
     '''Describe how to store this data in an HDF5 NeXus file'''
     write_dataset(h5parent, "comments", '\n'.join(map(str, scan.comments)))
コード例 #25
0
    def save(self, hfile = None, key = None):
        '''
        save the reduced data group to an HDF5 file, return filename or None if not written

        :param str hfile: output HDF5 file name (default: input HDF5 file)
        :param str key: name of reduced data set (default: nothing will be saved)

        By default, save to the input HDF5 file.
        To override this, specify the output HDF5 file name when calling this method.

        * If the file exists, this will not overwrite any input data.
        * Full, reduced :math:`R(Q)` goes into NXdata group::

            /entry/areaDetector_reduced_full

        * any previous full reduced :math:`R(Q)` will be replaced.

        * It may replace the rebinned, reduced :math:`R(Q)`
          if a NXdata group of the same number of bins exists.
        * Rebinned, reduced :math:`R(Q)`  goes into NXdata group::

              /entry/areaDetector_reduced_<N>

          where ``<N>`` is the number of bins, such as (for 500 bins)::

              /entry/areaDetector_reduced_500

        :see: http://download.nexusformat.org/doc/html/classes/base_classes/NXentry.html
        :see: http://download.nexusformat.org/doc/html/classes/base_classes/NXdata.html
        '''
        key = str(key)
        if key not in self.reduced:
            return
        nxname = 'areaDetector_reduced_' + key
        hfile = hfile or self.hdf5_file_name
        ds = self.reduced[key]
        try:
            hdf = h5py.File(hfile, 'a')
        except IOError as _exc:
            # FIXME: some h5py problem in <h5py>/_hl/files.py, line 101
            # this fails: fid = h5f.open(name, h5f.ACC_RDWR, fapl=fapl)
            # with IOError that is improperly caught on next and then:
            # fid = h5f.create(name, h5f.ACC_EXCL, fapl=fapl, fcpl=fcpl) fails with IOError
            # since the second call has "name" with all lower case
            #
            # real problem is that these HDF5 files have the wrong uid/gid, as set by the Pilatus computer
            # TODO: fix each Pilatus and this problem will go away
            # TODO: change uid/gid on all the acquired HDF5 files (*.h5, *.hdf) under usaxscontrol:/share1/USAXS_data/2*
            # Files should be owned by usaxs:usaxs (1810:2026), but are owned by tomo2:usaxs (500:2026) as seen by usaxs@usaxscontrol
            # not enough to change the "umask" on the det@dec1122 computer, what else will fix this?
            pvwatch.logMessage( "Problem writing reduced data back to file: " + hfile )
            return
        if 'default' not in hdf.attrs:
            hdf.attrs['default'] = 'entry'
        nxentry = eznx.openGroup(hdf, 'entry', 'NXentry')
        if 'default' not in nxentry.attrs:
            nxentry.attrs['default'] = nxname
        nxdata = eznx.openGroup(nxentry,
                                nxname,
                                'NXdata',
                                signal='R',
                                axes='Q',
                                Q_indices=0,
                                timestamp=calc.iso8601_datetime(),
                                )
        for key in sorted(ds.keys()):
            try:
                _ds = eznx.write_dataset(nxdata, key, ds[key])
                if key in self.units:
                    eznx.addAttributes(_ds, units=self.units[key])
            except RuntimeError as e:
                pass        # TODO: reporting
        hdf.close()
        return hfile
コード例 #26
0
ファイル: test_eznx.py プロジェクト: JPHammonds/spec2nexus
    def test_example(self):
        root = eznx.makeFile('test.h5', creator='eznx', default='entry')
        nxentry = eznx.makeGroup(root, 'entry', 'NXentry', default='data')
        ds = eznx.write_dataset(nxentry, 'title', 'simple test data')
        nxdata = eznx.makeGroup(nxentry, 'data', 'NXdata', signal='counts', axes='tth', tth_indices=0)
        ds = eznx.write_dataset(nxdata, 'tth', [10.0, 10.1, 10.2, 10.3], units='degrees')
        ds = eznx.write_dataset(nxdata, 'counts', [1, 50, 1000, 5], units='counts', axes="tth")
        root.close()
        
        """
        Test the data file for this structure::
        
            test.h5:NeXus data file
              @creator = eznx
              @default = 'entry'
              entry:NXentry
                @NX_class = NXentry
                @default = 'data'
                title:NX_CHAR = simple test data
                data:NXdata
                  @NX_class = NXdata
                  @signal = 'counts'
                  @axes = 'tth'
                  @axes_indices = 0
                  counts:NX_INT64[4] = [1, 50, 1000, 5]
                    @units = counts
                    @axes = tth
                  tth:NX_FLOAT64[4] = [10.0, 10.1, 10.199999999999999, 10.300000000000001]
                    @units = degrees
        """
        self.assertTrue(os.path.exists("test.h5"))
        with h5py.File("test.h5", "r") as hp:
            root = hp["/"]
            self.assertEqual(root.attrs.get("creator"), "eznx")
            self.assertEqual(root.attrs.get("default"), "entry")

            nxentry = root["entry"]
            self.assertEqual(nxentry.attrs.get("NX_class"), "NXentry")
            self.assertEqual(nxentry.attrs.get("default"), "data")
            self.assertEqual(
                eznx.read_nexus_field(nxentry, "title").decode('utf8'),
                "simple test data")

            nxdata = nxentry["data"]
            self.assertEqual(nxdata.attrs.get("NX_class"), "NXdata")
            self.assertEqual(nxdata.attrs.get("signal"), "counts")
            self.assertEqual(nxdata.attrs.get("axes"), "tth")
            self.assertEqual(nxdata.attrs.get("tth_indices"), 0)
            
            # test the HDF5 structure
            counts = nxdata["counts"]
            self.assertEqual(counts.attrs.get("units"), "counts")
            self.assertEqual(counts.attrs.get("axes"), "tth")
            tth = nxdata["tth"]
            self.assertEqual(tth.attrs.get("units"), "degrees")

            # test the data
            fields = eznx.read_nexus_group_fields(nxentry, "data", "counts tth".split())
            counts = fields["counts"]
            self.assertEqual(len(counts), 4)
            self.assertEqual(counts[2], [1, 50, 1000, 5][2])
            tth = fields["tth"]
            self.assertEqual(len(tth), 4)
            self.assertEqual(tth[2], [10.0, 10.1, 10.2, 10.3][2])
コード例 #27
0
    def save(self, hfile=None, key=None):
        '''
        save the reduced data group to an HDF5 file, return filename or None if not written

        :param str hfile: output HDF5 file name (default: input HDF5 file)
        :param str key: name of reduced data set (default: nothing will be saved)

        By default, save to the input HDF5 file.
        To override this, specify the output HDF5 file name when calling this method.

        * If the file exists, this will not overwrite any input data.
        * Full, reduced :math:`R(Q)` goes into NXdata group::

            /entry/flyScan_reduced_full

        * any previous full reduced :math:`R(Q)` will be replaced.

        * It may replace the rebinned, reduced :math:`R(Q)`
          if a NXdata group of the same number of bins exists.
        * Rebinned, reduced :math:`R(Q)`  goes into NXdata group::

              /entry/flyScan_reduced_<N>

          where ``<N>`` is the number of bins, such as (for 500 bins)::

              /entry/flyScan_reduced_500

        :see: http://download.nexusformat.org/doc/html/classes/base_classes/NXentry.html
        :see: http://download.nexusformat.org/doc/html/classes/base_classes/NXdata.html
        '''
        # TODO: save with NXprocess/NXdata structure
        # TODO: link that NXdata up to NXentry level
        # TODO: change /NXentry@default to point to best NXdata reduced
        # TODO: What about NXcanSAS?
        key = str(key)
        if key not in self.reduced:
            return
        nxname = 'flyScan_reduced_' + key
        hfile = hfile or self.hdf5_file_name
        ds = self.reduced[key]
        with h5py.File(hfile, 'a') as hdf:
            if 'default' not in hdf.attrs:
                hdf.attrs['default'] = 'entry'
            nxentry = eznx.openGroup(hdf, 'entry', 'NXentry')
            if 'default' not in nxentry.attrs:
                nxentry.attrs['default'] = nxname
            nxdata = eznx.openGroup(
                nxentry,
                nxname,
                'NXdata',
                signal='R',
                axes='Q',
                Q_indices=0,
                timestamp=calc.iso8601_datetime(),
            )
            for key in sorted(ds.keys()):
                try:
                    _ds = eznx.write_dataset(nxdata, key, ds[key])
                    if key in self.units:
                        eznx.addAttributes(_ds, units=self.units[key])
                except RuntimeError as e:
                    pass  # TODO: reporting

        return hfile
コード例 #28
0
    signal='frames',
)
nxinstrument = eznx.makeGroup(nxentry, 'instrument', 'NXinstrument')
nxdetector = eznx.makeGroup(nxinstrument, 'detector', 'NXdetector')
nxsource = eznx.makeGroup(nxinstrument, 'source', 'NXsource')
nxmonochromator = eznx.makeGroup(nxinstrument, 'monochromator',
                                 'NXmonochromator')
nxcollimator = eznx.makeGroup(nxinstrument, 'collimator', 'NXcollimator')
nxgeometry_slit = eznx.makeGroup(nxcollimator, 'geometry', 'NXgeometry')
nxshape_slit = eznx.makeGroup(nxgeometry_slit, 'shape', 'NXshape')
nxsample = eznx.makeGroup(nxinstrument, 'sample', 'NXsample')
nxmonitor = eznx.makeGroup(nxinstrument, 'control', 'NXmonitor')

# various metadata
eznx.addAttributes(root, creator=h5.attrs['creator'] + ' and spec2nexus.eznx')
eznx.write_dataset(nxentry, 'title', 'NeXus NXsas example')
eznx.write_dataset(
    nxentry,
    'definition',
    'NXsas',
    URL=
    'http://download.nexusformat.org/doc/html/classes/applications/NXsas.html')
eznx.write_dataset(nxentry, 'start_time', h5_files[0].attrs['file_time'])
eznx.write_dataset(nxentry, 'end_time', h5_files[-1].attrs['file_time'])
eznx.write_dataset(nxdetector, 'frame_files', '\n'.join(names))
eznx.write_dataset(nxinstrument, 'name', 'APS 9-ID-C USAXS pinSAXS')
eznx.write_dataset(nxsource, 'type', 'Synchrotron X-ray Source')
eznx.write_dataset(nxsource, 'name',
                   'Advanced Photon Source Undulator A, sector 9ID-C')
eznx.write_dataset(nxsource, 'probe', 'x-ray')
eznx.write_dataset(nxsource,