def test_is_Bluesky_specfile(): folder = join("polartools", "tests", "data_for_test") # Tests with spec loading within polartools. result = load_data.is_Bluesky_specfile("pressure_calibration.dat", folder=folder) assert result is False result = load_data.is_Bluesky_specfile("bluesky_spec.dat", folder=folder) assert result is True result = load_data.is_Bluesky_specfile("absorption.dat", folder=folder) assert result is False # Tests loading the spec file here. spec_file = SpecDataFile(join(folder, "pressure_calibration.dat")) result = load_data.is_Bluesky_specfile(spec_file) assert result is False spec_file = SpecDataFile(join(folder, "bluesky_spec.dat")) result = load_data.is_Bluesky_specfile(spec_file) assert result is True spec_file = SpecDataFile(join(folder, "absorption.dat")) result = load_data.is_Bluesky_specfile(spec_file) assert result is False
def load_spec_file(self): if self.spec_fname == '': self.status.showMessage('No file was loaded') return self.scan.scans_box.clear() try: self._spec_file = SpecDataFile(self.spec_fname) self._commands_list = self._spec_file.getScanCommands() for i in range(len(self._commands_list)): if '#S' in self._commands_list[i]: self._commands_list[i] = self._commands_list[i].strip( '#S ') self.scan.scans_box.addItem(self._commands_list[i]) self.scan.scans_box.setCurrentIndex(len(self._commands_list) - 1) self.selected_scan(self._commands_list[-1]) self.make_plot() self.pressure.print_pressure.setText('') except: self.status.showMessage('{} is not a spec file!!'.format( self.spec.fname.text()))
def load_spec(scan_id, spec_file, folder=""): """ Load data from spec file. If `spec_file` is the file name, it will load the spec file internally which is time consuming. Parameters ---------- scan_id : int Scan_id of the scan to be retrieved. spec_file : string or spec2nexus.spec.SpecDataFile Either the spec file name or a SpecDataFile instance. folder : string, optional Folder where spec file is located. Returns ------- data : pandas.DataFrame Table with the data from scan. See also -------- :func:`spec2nexus.spec.SpecDataFile` """ if isinstance(spec_file, str): path = join(folder, spec_file) spec_file = SpecDataFile(path) return DataFrame(spec_file.getScan(scan_id).data)
def openFile(self): fileName = qtWidgets.QFileDialog.getOpenFileName( None, "Open Spec File")[0] self.specFile = SpecDataFile(fileName) self.setWindowTitle(APP_NAME + ' - ' + str(fileName)) firstScan = self.specFile.getFirstScanNumber() self.positionerSelector.loadPositioners( self.specFile.scans[firstScan].positioner)
def testLoadScans(self): specFile = os.path.join(self.dataPath, FLUORESCENCE_FILE) print("SpecDataFile %s" % specFile) specData = SpecDataFile(specFile) self.scanBrowser.loadScans(specData.scans, newFile=True) self.assertEqual(len(self.spyLoaded), 1) self.assertEqual(len(self.spySelected), 0) self.assertEqual(self.scanBrowser.scanList.rowCount(), len(specData.getScanNumbers()))
def testName(self): spec_data = SpecDataFile(self.fname) self.assertTrue(isinstance(spec_data, SpecDataFile)) scan = spec_data.getScan(1) with self.assertRaises(spec2nexus.plugins.uxml.UXML_Error) as context: scan.interpret() received = str(context.exception) expected = "UXML error: Element 'group': " expected += "Character content other than whitespace is not allowed " expected += "because the content type is 'element-only'." self.assertTrue(received.startswith(expected))
def setUp(self): self.specDisplay = SpecDisplay() self.dataPath = os.environ.get(DATAPATH) specFileName1 = os.path.join(self.dataPath, FLUORESCENCE_FILE) try: self.specFile1 = SpecDataFile(specFileName1) except Exception as ex: self.fail(ex) specFileName2 = os.path.join(self.dataPath, FLUORESCENCE_FILE) try: self.specFile2 = SpecDataFile(specFileName2) except Exception as ex: self.fail(ex)
def test_xrd_calibrate_pressure(): path = join('polartools', 'tests', 'data_for_test') # Au calibrant pressure = xrd_calibrate_pressure(419, 'pressure_calibration.dat', temperature=9, energy=12.0, positioner='4C Two Theta', detector='CyberMag', monitor='IC3', folder=path) assert allclose(pressure, 0.743387, atol=1e-5) # Ag calibrant spec_file = SpecDataFile(join(path, 'pressure_calibration.dat')) pressure = xrd_calibrate_pressure(419, spec_file, temperature=9, energy=12.0, calibrant='Ag', positioner='4C Two Theta', detector='CyberMag', monitor='IC3') assert allclose(pressure, 0.818770, atol=1e-5)
class PositionerSelectorExample(BaseExample): def __init__(self, parent=None): super(PositionerSelectorExample, self).__init__(parent) self.positionerSelector = PositionerSelector() menuBar = self.menuBar() dataMenu = menuBar.addMenu("Data") self.dumpAction = qtWidgets.QAction("DumpSelected", self) dataMenu.addAction(self.dumpAction) self.dumpAction.triggered.connect(self.dumpSelectedData) self.setCentralWidget(self.positionerSelector) self.connectOpenFileAction(self.openFile) self.setWindowTitle(APP_NAME) self.show() @qtCore.pyqtSlot() def openFile(self): fileName = qtWidgets.QFileDialog.getOpenFileName( None, "Open Spec File")[0] self.specFile = SpecDataFile(fileName) self.setWindowTitle(APP_NAME + ' - ' + str(fileName)) firstScan = self.specFile.getFirstScanNumber() self.positionerSelector.loadPositioners( self.specFile.scans[firstScan].positioner) def dumpSelectedData(self): print(self.positionerSelector.getSelectedItems())
def testScanSelected(self): selectedScan = 5 specFile = os.path.join(self.dataPath, FLUORESCENCE_FILE) spyLoaded = QSignalSpy(self.scanBrowser.scanLoaded) specData = SpecDataFile(specFile) self.scanBrowser.loadScans(specData.scans) self.assertEqual(len(spyLoaded), 1) self.assertEqual(len(self.spySelected), 0) self.scanBrowser.setCurrentScan(selectedScan) self.assertEqual(len(spyLoaded), 1) self.assertEqual(len(self.spySelected), 1) self.assertEqual(self.scanBrowser.getCurrentScan(), '6') self.scanBrowser.filterByScanTypes(specData.scans, SCAN_TYPES[2]) self.assertEqual(len(spyLoaded), 2) self.assertEqual(len(self.spySelected), 1) # Doesn't register a selection change since row has not changed self.scanBrowser.setCurrentScan(selectedScan) self.assertEqual(len(spyLoaded), 2) self.assertEqual(len(self.spySelected), 1) self.assertEqual(self.scanBrowser.getCurrentScan(), '12') # Register a selection change since row changed self.scanBrowser.setCurrentScan(selectedScan + 1) self.assertEqual(len(spyLoaded), 2) self.assertEqual(len(self.spySelected), 2) self.assertEqual(self.scanBrowser.getCurrentScan(), '13')
def openFile(self): ''' Open a file, populate the navigator window as appropriate ''' logger.debug(METHOD_ENTER_STR) fOptions = qtWidgets.QFileDialog.Options() fOptions |= qtWidgets.QFileDialog.DontUseNativeDialog fileName = qtWidgets.QFileDialog.getOpenFileName( self, caption="Open Spec File", directory=self.currentDirectory, options=fOptions)[0] specFile = None if fileName != "": try: specFile = SpecDataFile(fileName) except NotASpecDataFile as ex: qtWidgets.QMessageBox.warning( self, "Not a Spec File", "The file %s does not seem to be a spec file" % fileName) return self.currentDirectory = str(os.path.realpath(fileName)) else: return self._dataNavigator.addSpecDataFileNode(specFile)
def is_Bluesky_specfile(source, folder=""): """ Check if the specfile was created by Bluesky. It looks for a "Bluesky" comment in the file header. Parameters ---------- source : string or spec2nexus.spec.SpecDataFile Either the spec file name or a SpecDataFile instance. folder : string, optional Folder where spec file is located. Returns ------- y : bool True if spec_file was generated by Bluesky, False otherwise. See also -------- :func:`spec2nexus.spec.SpecDataFile` """ if isinstance(source, str): path = join(folder, source) source = SpecDataFile(path) if len(source.headers[0].comments): return source.headers[0].comments[0].startswith("Bluesky") else: return False
def setUp(self): self.selection = IntermediateDataSelection() print(dir (self.selection)) self.dataPath = os.environ.get(DATAPATH) specDataFileName = os.path.join(self.dataPath, FLUORESCENCE_FILE) specDataFile = SpecDataFile(specDataFileName) specNode = SpecFileDataNode(specDataFile)
def choose_file(self): ''' Opens file dialog, set file text box to the chosen path ''' from spec2nexus.spec import SpecDataFile dirname = self.get_default_directory(self.filename.text()) filename = getOpenFileName(self, 'Open file', dirname) if os.path.exists(filename): self.filename.setText(str(filename)) self.spec = SpecDataFile(self.get_filename()) self.set_default_directory(os.path.dirname(filename)) scan_min = self.spec.getMinScanNumber() self.scanmin.setText(str(scan_min)) scan_max = self.spec.getMaxScanNumber() self.scanmax.setText(str(scan_max))
def __init__(self, specPath): super(SpecFile, self).__init__(parent=None) self.specFilePath = specPath self.specFile = SpecDataFile(specPath) self.scanBrowser = ScanBrowser() self.scanBrowser.loadScans(self.getScans(), self) self.selectedScans = []
def specFileInfo(self): """This method sets the name, status tip for the spec file, and loads the scan to the list from the spec file. """ self.rdOnlyFileName.setText(self.readSpec.specFileName) self.rdOnlyFileName.setStatusTip(self.readSpec.specFileName) specFile = SpecDataFile(self.readSpec.specFileName) self.readSpec.loadScans(specFile.scans)
def __init__(self, specfile): if os.path.exists(specfile): from spec2nexus.spec import SpecDataFile self.filename = specfile stat = os.stat(specfile) self.size = stat.st_size self.mtime = stat.st_mtime self.sdf_object = SpecDataFile(specfile)
def test_contents(self): spec_data = SpecDataFile(self.fname) self.assertTrue(isinstance(spec_data, SpecDataFile)) out = writer.Writer(spec_data) scan_list = [ 1, ] out.save(self.hname, scan_list) # text that UXML group defined as expected self.assertTrue(os.path.exists(self.hname)) with h5py.File(self.hname) as h5_file: self.assertTrue("S1" in h5_file) nxentry = h5_file["/S1"] self.assertTrue("UXML" in nxentry) uxml = nxentry["UXML"] self.assertTrue("NX_class" in uxml.attrs) self.assertEqual(uxml.attrs["NX_class"], "NXnote") # spot-check a couple items # group: attenuator_set self.assertTrue("attenuator_set" in uxml) group = uxml["attenuator_set"] prefix = group.attrs.get("prefix") description = group.attrs.get("description") unique_id = group.attrs.get("unique_id") self.assertEqual(prefix, "33idd:filter:") self.assertEqual(description, "33-ID-D Filters") self.assertEqual(unique_id, None) # <dataset name="corrdet_counter">corrdet</dataset> self.assertTrue("corrdet_counter" in group) ds = group["corrdet_counter"] # http://docs.h5py.org/en/stable/whatsnew/2.1.html?highlight=dataset#dataset-value-property-is-now-deprecated value = ds[()] # ds.value deprecated in h5py self.assertEqual(value, [b"corrdet"]) # <dataset name="wait_time" type="float" units="s">0.500</dataset> self.assertTrue("wait_time" in group) ds = group["wait_time"] attrs = dict(ds.attrs) self.assertEqual(ds.attrs.get("units"), "s") value = ds[()] # ds.value deprecated in h5py self.assertEqual(value, numpy.array([.5])) # <hardlink name="attenuator1" target_id="33idd:filter:Fi1:"/> self.assertTrue("attenuator1" in group) attenuator1 = group["attenuator1"] target = attenuator1.attrs.get("target") self.assertNotEqual(target, attenuator1.name) self.assertEqual(target, uxml["attenuator1"].name) addr = "/S1/UXML/ad_file_info/file_format" self.assertTrue(addr in h5_file) ds = h5_file[addr] value = ds[()] # ds.value deprecated in h5py self.assertEqual(value, [b"TIFF"])
def testName(self): spec_data = SpecDataFile(self.fname) self.assertTrue(isinstance(spec_data, SpecDataFile)) out = writer.Writer(spec_data) scan_list = [ 1, ] out.save(self.hname, scan_list) # TODO: make tests of other things in the Writer dd = out.root_attributes() self.assertTrue(isinstance(dd, dict))
def loadSpec(self, specFile, directory): """This method loads the spec file and creates the widgets on the control QDockWidget. """ self.chambers = [] self.specFile = SpecDataFile(specFile) self.specHeader = SpecDataFileHeader(specFile) self.scans = self.specFile.scans self.scan = str(int(os.path.basename(directory))) self.specFileOpened = True self.maxScans = self.specFile.getMaxScanNumber() # Gets possible normalizer values for key in self.scans[self.scan].data.keys(): if key.find("Ion_Ch_") == 0: self.chambers.append(key) self.chambers.sort() self.MonDialog() self.mainWindow.controlDockWidget.close() self.mainWindow.ControlDockWidget()
def choose_file(self): ''' Opens file dialog, set file text box to the chosen path ''' dirname = self.get_default_directory(self.filename.text()) filename = getOpenFileName(self, 'Open file', dirname) if os.path.exists(filename): self.filename.setText(str(filename)) self.spec = SpecDataFile(self.get_filename()) self.set_default_directory(os.path.dirname(filename)) scan_min = self.spec.getMinScanNumber() self.scanmin.setText(str(scan_min)) scan_max = self.spec.getMaxScanNumber() self.scanmax.setText(str(scan_max))
def choose_file(self): """Opens file dialog, set file text box to the chosen path.""" from spec2nexus.spec import SpecDataFile dirname = self.get_default_directory(self.filename.text()) filename = getOpenFileName(self, 'Open file', dirname) if os.path.exists(filename): self.filename.setText(str(filename)) self.spec = SpecDataFile(self.get_filename()) self.set_default_directory(os.path.dirname(filename)) all_scans = self.get_scan_numbers() scan_min = all_scans[0] self.scanmin.setText(str(scan_min)) scan_max = all_scans[-1] self.scanmax.setText(str(scan_max))
def reload(self): logger.debug(METHOD_ENTER_STR) scanKeys = sorted(self._specDataFile.scans, key=int) logger.debug("Unload the old data") filename = self._specDataFile.fileName for scan in scanKeys: logger.debug("scan to remove %s" % self.scans[scan].__class__) self.removeSpecScan(scan) for scan in self._specDataFile.scans: scan = None self._specDataFile = None gc.collect logger.debug("Load current data in the file") self._specDataFile = SpecDataFile(filename) self.loadScans() gc.collect()
def _browseForPathToReplace(self): if os.path.exists(str(self.projNameTxt.text())) and \ (str(self.scanNumsTxt.text()) != ""): specFile = str(self.projNameTxt.text()) scans = self.getScanList() sd = SpecDataFile(specFile) scan = sd.scans[str(scans[0])] scan.interpret() if scan.CCD != None: try: filePath = scan.CCD['image_dir'][0] self.pathToReplaceTxt.setText(filePath) except: qtWidgets.QMessageBox.warning(self, "File patgh not Found", \ "File path not found for scan %s" \ % scan) self.pathToReplaceTxt.editingFinished.emit()
def testFilterByScanTypes(self): specFile = os.path.join(self.dataPath, FLUORESCENCE_FILE) spyLoaded = QSignalSpy(self.scanBrowser.scanLoaded) specData = SpecDataFile(specFile) self.scanBrowser.loadScans(specData.scans) self.assertEqual(len(spyLoaded), 1) self.assertEqual(len(self.spySelected), 0) self.scanBrowser.filterByScanTypes(specData.scans, SCAN_TYPES[1]) self.assertEqual(self.scanBrowser.scanList.rowCount(), NUM_SCAN_TYPES[1]) self.scanBrowser.filterByScanTypes(specData.scans, SCAN_TYPES[2]) self.assertEqual(self.scanBrowser.scanList.rowCount(), NUM_SCAN_TYPES[2]) self.scanBrowser.filterByScanTypes(specData.scans, SCAN_TYPES[3]) self.assertEqual(self.scanBrowser.scanList.rowCount(), NUM_SCAN_TYPES[3]) self.scanBrowser.filterByScanTypes(specData.scans, SCAN_TYPES[4]) self.assertEqual(self.scanBrowser.scanList.rowCount(), NUM_SCAN_TYPES[4]) self.scanBrowser.filterByScanTypes(specData.scans, SCAN_TYPES[5]) self.assertEqual(self.scanBrowser.scanList.rowCount(), NUM_SCAN_TYPES[5]) self.scanBrowser.filterByScanTypes(specData.scans, SCAN_TYPES[6]) self.assertEqual(self.scanBrowser.scanList.rowCount(), NUM_SCAN_TYPES[6]) self.scanBrowser.filterByScanTypes(specData.scans, SCAN_TYPES[7]) self.assertEqual(self.scanBrowser.scanList.rowCount(), NUM_SCAN_TYPES[7]) self.scanBrowser.filterByScanTypes(specData.scans, SCAN_TYPES[8]) self.assertEqual(self.scanBrowser.scanList.rowCount(), NUM_SCAN_TYPES[8]) self.scanBrowser.filterByScanTypes(specData.scans, SCAN_TYPES[1:]) self.assertEqual(self.scanBrowser.scanList.rowCount(), NUM_SCAN_TYPES[0]) self.scanBrowser.filterByScanTypes(specData.scans, []) self.assertEqual(self.scanBrowser.scanList.rowCount(), NUM_SCAN_TYPES[0]) with self.assertRaises(ValueError): self.scanBrowser.filterByScanTypes(specData.scans, None) self.assertEqual(NUM_SCAN_TYPES[0], sum(NUM_SCAN_TYPES[1:])) self.assertEqual(len(spyLoaded), 11) self.assertEqual(len(self.spySelected), 0)
def test_contents(self): spec_data = SpecDataFile(self.fname) self.assertTrue(isinstance(spec_data, SpecDataFile)) out = writer.Writer(spec_data) scan_list = [ 1, ] out.save(self.hname, scan_list) # the ONLY structural difference between test_3.spec # and test_4.spec is the presence of this hardlink self.assertTrue(os.path.exists(self.hname)) with h5py.File(self.hname) as h5_file: source = h5_file["/S1/UXML/ad_detector/beam_center_x"] link = h5_file["/S1/UXML/beam_center_x"] target = source.attrs.get("target") self.assertNotEqual(source.name, link.name) self.assertNotEqual(target, None) self.assertEqual(target, source.name) self.assertEqual(target, link.attrs.get("target"))
class Sector33SpecDataSource(SpecXMLDrivenDataSource): ''' Class to load data from spec file and configuration xml files from for the way that data is collected at sector 33. :members ''' def __init__(self, projectDir, projectName, projectExtension, instConfigFile, detConfigFile, **kwargs): ''' Constructor :param projectDir: Directory holding the project file to open :param projectName: First part of file name for the project :param projectExt: File extension for the project file. :param instConfigFile: Full path to Instrument configuration file. :param detConfigFile: Full path to the detector configuration file :param kwargs: Assorted keyword arguments :rtype: Sector33SpecDataSource ''' super(Sector33SpecDataSource, self).__init__(projectDir, projectName, projectExtension, instConfigFile, detConfigFile, **kwargs) def _calc_eulerian_from_kappa(self, primaryAngles=None, referenceAngles = None): """ Calculate the eulerian sample angles from the kappa stage angles. :param primaryAngles: list of sample axis numbers to be handled by the conversion :param referenceAngles: list of reference angles to be used in angle conversion """ keta = np.deg2rad(referenceAngles[:,0]) kappa = np.deg2rad(referenceAngles[:,1]) kphi = np.deg2rad(referenceAngles[:,2]) kappaParam = self.instConfig.getSampleAngleMappingParameter('kappa') try: if kappaParam != None: self.kalpha = np.deg2rad(float(kappaParam)) else: self.kalpha = np.deg2rad(50.000) kappaInvertedParam = \ self.instConfig.getSampleAngleMappingParameter('kappaInverted') if kappaInvertedParam != None: self.kappa_inverted = self.to_bool(kappaInvertedParam) else: self.kappa_inverted = False except Exception as ex: raise RSMap3DException("Error trying to get parameter for " + \ "sampleAngleMappingFunction " + \ "_calc_eulerian_from_kappa in inst config " + \ "file\n" + \ str(ex)) _t1 = np.arctan(np.tan(kappa / 2.0) * np.cos(self.kalpha)) if self.kappa_inverted: eta = np.rad2deg(keta + _t1) phi = np.rad2deg(kphi + _t1) else: eta = np.rad2deg(keta - _t1) phi = np.rad2deg(kphi - _t1) chi = 2.0 * np.rad2deg(np.arcsin(np.sin(kappa / 2.0) * \ np.sin(self.kalpha))) return eta, chi, phi def _calc_replace_angle_values(self , primaryAngles=None, referenceAngles=None): ''' Fix a situation were some constant angle values have been recorded incorrectly and need to be fixed. :param primaryAngles: list of sample axis numbers to be handled by the conversion :param referenceAngles: list of reference angles to be used in angle conversion ''' logger.info( "Running " + __name__) angles = [] logger.debug("referenceAngles " + str(referenceAngles)) mappingAngles = self.instConfig.getSampleAngleMappingReferenceAngles() logger.debug( "mappingAngles" + str(mappingAngles)) for ii in range(len(referenceAngles)): replaceVal = \ float(self.instConfig.getSampleAngleMappingReferenceAngleAttrib( \ number= str(mappingAngles[ii]), \ attribName='replaceValue')) logger.debug( "primary Angles" + str(referenceAngles)) angles.append(replaceVal* np.ones(len(referenceAngles[:,ii]),)) logger.debug("Angles" + str( angles)) return angles def fixGeoAngles(self, scan, angles): ''' Fix the angles using a user selected function. :param scan: scan to set the angles for :param angles: Array of angles to set for this scan ''' logger.debug( "starting " + __name__) needToCorrect = False refAngleNames = self.instConfig.getSampleAngleMappingReferenceAngles() for refAngleName in refAngleNames: alwaysFix = self.instConfig.getSampleAngleMappingAlwaysFix() if refAngleName in scan.L or alwaysFix: needToCorrect = True if needToCorrect: logger.debug( __name__ + ": Fixing angles") refAngles = self.getScanAngles(scan, refAngleNames) primaryAngles = self.instConfig.getSampleAngleMappingPrimaryAngles() functionName = self.instConfig.getSampleAngleMappingFunctionName() functionModuleName = self.instConfig.getSampleAngleMappingFunctionModule() logger.debug("sampleMappingFunction moduleName %s" % functionModuleName) #Call a defined method to calculate angles from the reference angles. moduleSource = self if functionModuleName != None: functionModule = importlib.import_module(functionModuleName) logger.debug("dir(functionModule)" % dir(functionModule)) moduleSource = functionModule method = getattr(moduleSource, functionName) fixedAngles = method(primaryAngles=primaryAngles, referenceAngles=refAngles) logger.debug ("fixed Angles: " + str(fixedAngles)) for i in range(len(primaryAngles)): logger.debug ("Fixing primaryAngles: %d " % primaryAngles[i]) angles[:,primaryAngles[i]-1] = fixedAngles[i] def getGeoAngles(self, scan, angleNames): """ This function returns all of the geometry angles for the for the scan as a N-by-num_geo array, where N is the number of scan points and num_geo is the number of geometry motors. """ # scan = self.sd[scanNo] geoAngles = self.getScanAngles(scan, angleNames) if not (self.instConfig.getSampleAngleMappingFunctionName() == ""): tb = None try: self.fixGeoAngles(scan, geoAngles) except Exception as ex: tb = traceback.format_exc() raise RSMap3DException("Handling exception in getGeoAngles." + \ "\n" + \ str(ex) + \ "\n" + \ str(tb)) logger.debug("getGeoAngles:\n" + str(geoAngles)) return geoAngles def getUBMatrix(self, scan): """ Read UB matrix from the #G3 line from the spec file. """ try: g3 = scan.G["G3"].strip().split() g3 = np.array(list(map(float, g3))) ub = g3.reshape(-1,3) logger.debug("ub " +str(ub)) return ub except: logger.error("Unable to read UB Matrix from G3") logger.error( '-'*60) traceback.print_exc(file=sys.stdout) logger.error('-'*60) def hotpixelkill(self, areaData): """ function to remove hot pixels from CCD frames ADD REMOVE VALUES IF NEEDED! :param areaData: area detector data """ for pixel in self.getBadPixels(): badLoc = pixel.getBadLocation() replaceLoc = pixel.getReplacementLocation() areaData[badLoc[0],badLoc[1]] = \ areaData[replaceLoc[0],replaceLoc[1]] return areaData def loadSource(self, mapHKL=False): ''' This method does the work of loading data from the files. This has been split off from the constructor to allow this to be threaded and later canceled. :param mapHKL: boolean to mark if the data should be mapped to HKL ''' # Load up the instrument configuration file self.loadInstrumentXMLConfig() #Load up the detector configuration file self.loadDetectorXMLConfig() self.specFile = os.path.join(self.projectDir, self.projectName + \ self.projectExt) imageDir = os.path.join(self.projectDir, \ IMAGE_DIR_MERGE_STR % self.projectName) self.imageFileTmp = os.path.join(imageDir, \ TIFF_FILE_MERGE_STR % (self.projectName)) # if needed load up the bad pixel file. if not (self.badPixelFile is None): badPixelFile = PilatusBadPixelFile(self.badPixelFile) self.badPixels = badPixelFile.getBadPixels() # id needed load the flat field file if not (self.flatFieldFile is None): self.flatFieldData = np.array(Image.open(self.flatFieldFile)).T # Load scan information from the spec file try: self.sd = SpecDataFile(self.specFile) self.mapHKL = mapHKL maxScan = int(self.sd.getMaxScanNumber()) logger.debug("Number of Scans" + str(maxScan)) if self.scans is None: self.scans = range(1, maxScan+1) imagePath = os.path.join(self.projectDir, IMAGE_DIR_MERGE_STR % self.projectName) self.imageBounds = {} self.imageToBeUsed = {} self.availableScans = [] self.incidentEnergy = {} self.ubMatrix = {} self.scanType = {} self.progress = 0 self.progressInc = 1 # Zero the progress bar at the beginning. if self.progressUpdater is not None: self.progressUpdater(self.progress, self.progressMax) for scan in self.scans: if (self.cancelLoad): self.cancelLoad = False raise LoadCanceledException(CANCEL_STR) else: if (os.path.exists(os.path.join(imagePath, \ SCAN_NUMBER_MERGE_STR % scan))): try: curScan = self.sd.scans[str(scan)] self.scanType[scan] = \ self.sd.scans[str(scan)].scanCmd.split()[0] angles = self.getGeoAngles(curScan, self.angleNames) self.availableScans.append(scan) if self.mapHKL==True: self.ubMatrix[scan] = self.getUBMatrix(curScan) if self.ubMatrix[scan] is None: raise Sector33SpecFileException("UB matrix " + \ "not found.") else: self.ubMatrix[scan] = None self.incidentEnergy[scan] = 12398.4 /float(curScan.G['G4'].split()[3]) _start_time = time.time() self.imageBounds[scan] = \ self.findImageQs(angles, \ self.ubMatrix[scan], \ self.incidentEnergy[scan]) if self.progressUpdater is not None: self.progressUpdater(self.progress, self.progressMax) logger.info (('Elapsed time for Finding qs for scan %d: ' + '%.3f seconds') % \ (scan, (time.time() - _start_time))) except ScanDataMissingException: logger.error( "Scan " + str(scan) + " has no data") #Make sure to show 100% completion if self.progressUpdater is not None: self.progressUpdater(self.progressMax, self.progressMax) except IOError: raise IOError( "Cannot open file " + str(self.specFile)) if len(self.getAvailableScans()) == 0: raise ScanDataMissingException("Could not find scan data for " + \ "input file \n" + self.specFile + \ "\nOne possible reason for this " + \ "is that the image files are " + \ "missing. Images are assumed " + \ "to be in " + \ os.path.join(self.projectDir, IMAGE_DIR_MERGE_STR % self.projectName)) self.availableScanTypes = set(self.scanType.values()) def to_bool(self, value): """ Note this method found in answer to: http://stackoverflow.com/questions/715417/converting-from-a-string-to-boolean-in-python Converts 'something' to boolean. Raises exception if it gets a string it doesn't handle. Case is ignored for strings. These string values are handled: True: 'True', "1", "TRue", "yes", "y", "t" False: "", "0", "faLse", "no", "n", "f" Non-string values are passed to bool. """ if type(value) == type(''): if value.lower() in ("yes", "y", "true", "t", "1"): return True if value.lower() in ("no", "n", "false", "f", "0", ""): return False raise Exception('Invalid value for boolean conversion: ' + value) return bool(value) def rawmap(self,scans, angdelta=[0,0,0,0,0], adframes=None, mask = None): """ read ad frames and and convert them in reciprocal space angular coordinates are taken from the spec file or read from the edf file header when no scan number is given (scannr=None) """ if mask is None: mask_was_none = True #mask = [True] * len(self.getImageToBeUsed()[scans[0]]) else: mask_was_none = False #sd = spec.SpecDataFile(self.specFile) intensity = np.array([]) # fourc goniometer in fourc coordinates # convention for coordinate system: # x: upwards; # y: along the incident beam; # z: "outboard" (makes coordinate system right-handed). # QConversion will set up the goniometer geometry. # So the first argument describes the sample rotations, the second the # detector rotations and the third the primary beam direction. qconv = xu.experiment.QConversion(self.getSampleCircleDirections(), \ self.getDetectorCircleDirections(), \ self.getPrimaryBeamDirection()) # define experimental class for angle conversion # # ipdir: inplane reference direction (ipdir points into the primary beam # direction at zero angles) # ndir: surface normal of your sample (ndir points in a direction # perpendicular to the primary beam and the innermost detector # rotation axis) en = self.getIncidentEnergy() hxrd = xu.HXRD(self.getInplaneReferenceDirection(), \ self.getSampleSurfaceNormalDirection(), \ en=en[self.getAvailableScans()[0]], \ qconv=qconv) # initialize area detector properties if (self.getDetectorPixelWidth() != None ) and \ (self.getDistanceToDetector() != None): hxrd.Ang2Q.init_area(self.getDetectorPixelDirection1(), \ self.getDetectorPixelDirection2(), \ cch1=self.getDetectorCenterChannel()[0], \ cch2=self.getDetectorCenterChannel()[1], \ Nch1=self.getDetectorDimensions()[0], \ Nch2=self.getDetectorDimensions()[1], \ pwidth1=self.getDetectorPixelWidth()[0], \ pwidth2=self.getDetectorPixelWidth()[1], \ distance=self.getDistanceToDetector(), \ Nav=self.getNumPixelsToAverage(), \ roi=self.getDetectorROI()) else: hxrd.Ang2Q.init_area(self.getDetectorPixelDirection1(), \ self.getDetectorPixelDirection2(), \ cch1=self.getDetectorCenterChannel()[0], \ cch2=self.getDetectorCenterChannel()[1], \ Nch1=self.getDetectorDimensions()[0], \ Nch2=self.getDetectorDimensions()[1], \ chpdeg1=self.getDetectorChannelsPerDegree()[0], \ chpdeg2=self.getDetectorChannelsPerDegree()[1], \ Nav=self.getNumPixelsToAverage(), roi=self.getDetectorROI()) angleNames = self.getAngles() scanAngle = {} for i in range(len(angleNames)): scanAngle[i] = np.array([]) offset = 0 imageToBeUsed = self.getImageToBeUsed() monitorName = self.getMonitorName() monitorScaleFactor = self.getMonitorScaleFactor() filterName = self.getFilterName() filterScaleFactor = self.getFilterScaleFactor() for scannr in scans: if self.haltMap: raise ProcessCanceledException("Process Canceled") scan = self.sd.scans[str(scannr)] angles = self.getGeoAngles(scan, angleNames) scanAngle1 = {} scanAngle2 = {} for i in range(len(angleNames)): scanAngle1[i] = angles[:,i] scanAngle2[i] = [] if monitorName != None: monitor_data = scan.data.get(monitorName) if monitor_data is None: raise IOError("Did not find Monitor source '" + \ monitorName + \ "' in the Spec file. Make sure " + \ "monitorName is correct in the " + \ "instrument Config file") if filterName != None: filter_data = scan.data.get(filterName) if filter_data is None: raise IOError("Did not find filter source '" + \ filterName + \ "' in the Spec file. Make sure " + \ "filterName is correct in the " + \ "instrument Config file") # read in the image data arrayInitializedForScan = False foundIndex = 0 if mask_was_none: mask = [True] * len(self.getImageToBeUsed()[scannr]) for ind in range(len(scan.data[list(scan.data.keys())[0]])): if imageToBeUsed[scannr][ind] and mask[ind]: # read tif image im = Image.open(self.imageFileTmp % (scannr, scannr, ind)) img = np.array(im.getdata()).reshape(im.size[1],im.size[0]).T img = self.hotpixelkill(img) ff_data = self.getFlatFieldData() if not (ff_data is None): img = img * ff_data # reduce data siz img2 = xu.blockAverage2D(img, self.getNumPixelsToAverage()[0], \ self.getNumPixelsToAverage()[1], \ roi=self.getDetectorROI()) # apply intensity corrections if monitorName != None: img2 = img2 / monitor_data[ind] * monitorScaleFactor if filterName != None: img2 = img2 / filter_data[ind] * filterScaleFactor # initialize data array if not arrayInitializedForScan: imagesToProcess = [imageToBeUsed[scannr][i] and mask[i] for i in range(len(imageToBeUsed[scannr]))] if not intensity.shape[0]: intensity = np.zeros((np.count_nonzero(imagesToProcess),) + img2.shape) arrayInitializedForScan = True else: offset = intensity.shape[0] intensity = np.concatenate( (intensity, (np.zeros((np.count_nonzero(imagesToProcess),) + img2.shape))), axis=0) arrayInitializedForScan = True # add data to intensity array intensity[foundIndex+offset,:,:] = img2 for i in range(len(angleNames)): # logger.debug("appending angles to angle2 " + # str(scanAngle1[i][ind])) scanAngle2[i].append(scanAngle1[i][ind]) foundIndex += 1 if len(scanAngle2[0]) > 0: for i in range(len(angleNames)): scanAngle[i] = \ np.concatenate((scanAngle[i], np.array(scanAngle2[i])), \ axis=0) # transform scan angles to reciprocal space coordinates for all detector pixels angleList = [] for i in range(len(angleNames)): angleList.append(scanAngle[i]) if self.ubMatrix[scans[0]] is None: qx, qy, qz = hxrd.Ang2Q.area(*angleList, \ roi=self.getDetectorROI(), Nav=self.getNumPixelsToAverage()) else: qx, qy, qz = hxrd.Ang2Q.area(*angleList, \ roi=self.getDetectorROI(), Nav=self.getNumPixelsToAverage(), \ UB = self.ubMatrix[scans[0]]) # apply selected transform qxTrans, qyTrans, qzTrans = \ self.transform.do3DTransform(qx, qy, qz) return qxTrans, qyTrans, qzTrans, intensity
def loadSource(self, mapHKL=False): ''' This method does the work of loading data from the files. This has been split off from the constructor to allow this to be threaded and later canceled. :param mapHKL: boolean to mark if the data should be mapped to HKL ''' # Load up the instrument configuration file self.loadInstrumentXMLConfig() #Load up the detector configuration file self.loadDetectorXMLConfig() self.specFile = os.path.join(self.projectDir, self.projectName + \ self.projectExt) imageDir = os.path.join(self.projectDir, \ IMAGE_DIR_MERGE_STR % self.projectName) self.imageFileTmp = os.path.join(imageDir, \ TIFF_FILE_MERGE_STR % (self.projectName)) # if needed load up the bad pixel file. if not (self.badPixelFile is None): badPixelFile = PilatusBadPixelFile(self.badPixelFile) self.badPixels = badPixelFile.getBadPixels() # id needed load the flat field file if not (self.flatFieldFile is None): self.flatFieldData = np.array(Image.open(self.flatFieldFile)).T # Load scan information from the spec file try: self.sd = SpecDataFile(self.specFile) self.mapHKL = mapHKL maxScan = int(self.sd.getMaxScanNumber()) logger.debug("Number of Scans" + str(maxScan)) if self.scans is None: self.scans = range(1, maxScan+1) imagePath = os.path.join(self.projectDir, IMAGE_DIR_MERGE_STR % self.projectName) self.imageBounds = {} self.imageToBeUsed = {} self.availableScans = [] self.incidentEnergy = {} self.ubMatrix = {} self.scanType = {} self.progress = 0 self.progressInc = 1 # Zero the progress bar at the beginning. if self.progressUpdater is not None: self.progressUpdater(self.progress, self.progressMax) for scan in self.scans: if (self.cancelLoad): self.cancelLoad = False raise LoadCanceledException(CANCEL_STR) else: if (os.path.exists(os.path.join(imagePath, \ SCAN_NUMBER_MERGE_STR % scan))): try: curScan = self.sd.scans[str(scan)] self.scanType[scan] = \ self.sd.scans[str(scan)].scanCmd.split()[0] angles = self.getGeoAngles(curScan, self.angleNames) self.availableScans.append(scan) if self.mapHKL==True: self.ubMatrix[scan] = self.getUBMatrix(curScan) if self.ubMatrix[scan] is None: raise Sector33SpecFileException("UB matrix " + \ "not found.") else: self.ubMatrix[scan] = None self.incidentEnergy[scan] = 12398.4 /float(curScan.G['G4'].split()[3]) _start_time = time.time() self.imageBounds[scan] = \ self.findImageQs(angles, \ self.ubMatrix[scan], \ self.incidentEnergy[scan]) if self.progressUpdater is not None: self.progressUpdater(self.progress, self.progressMax) logger.info (('Elapsed time for Finding qs for scan %d: ' + '%.3f seconds') % \ (scan, (time.time() - _start_time))) except ScanDataMissingException: logger.error( "Scan " + str(scan) + " has no data") #Make sure to show 100% completion if self.progressUpdater is not None: self.progressUpdater(self.progressMax, self.progressMax) except IOError: raise IOError( "Cannot open file " + str(self.specFile)) if len(self.getAvailableScans()) == 0: raise ScanDataMissingException("Could not find scan data for " + \ "input file \n" + self.specFile + \ "\nOne possible reason for this " + \ "is that the image files are " + \ "missing. Images are assumed " + \ "to be in " + \ os.path.join(self.projectDir, IMAGE_DIR_MERGE_STR % self.projectName)) self.availableScanTypes = set(self.scanType.values())
def openFile(self, filename): '''open the SPEC file and get its data''' from spec2nexus.spec import SpecDataFile if os.path.exists(filename): self.SPECfile = SpecDataFile(filename)
class Parser(object): '''parse the spec data file object''' def __init__(self, spec_data=None): ''':param obj spec_data: instance of :class:`spec2nexus.prjPySpec.SpecDataFile`''' self.SPECfile = spec_data self.progress_bar = spec_data.progress_bar self.update_progress = spec_data.update_progress def openFile(self, filename): '''open the SPEC file and get its data''' from spec2nexus.spec import SpecDataFile if os.path.exists(filename): self.SPECfile = SpecDataFile(filename) def toTree(self, scan_list=[]): ''' convert scans from chosen SPEC file into NXroot object and structure called from nexpy.readers.readspec.ImportDialog.get_data__prjPySpec() after clicking <Ok> in dialog Each scan in the range from self.scanmin to self.scanmax (inclusive) will be converted to a NXentry. Scan data will go in a NXdata where the signal=1 is the last column and the corresponding axes= is the first column. :param [int] scanlist :raises: ValueError is Min or Max scan number are not given properly ''' import spec2nexus from spec2nexus import utils # check that scan_list is valid if len(scan_list) == 0: return None if self.SPECfile is None: return None complete_scan_list = list(self.SPECfile.scans) for key in [str(s) for s in scan_list]: if key not in complete_scan_list: msg = 'scan ' + str(key) + ' was not found' raise ValueError(msg) root = NXroot() root.attrs['spec2nexus'] = str(spec2nexus.__version__) header0 = self.SPECfile.headers[0] root.attrs['SPEC_file'] = self.SPECfile.fileName root.attrs['SPEC_epoch'] = header0.epoch root.attrs['SPEC_date'] = utils.iso8601(header0.date) root.attrs['SPEC_comments'] = '\n'.join(header0.comments) try: c = header0.comments[0] user = c[c.find('User = '******'=')[1].strip() root.attrs['SPEC_user'] = user except: pass root.attrs['SPEC_num_headers'] = len(self.SPECfile.headers) self.progress_bar.setVisible(True) self.progress_bar.setRange(scan_list[0], scan_list[-1]) for key in [str(s) for s in scan_list]: scan = self.SPECfile.getScan(key) scan.interpret() entry = NXentry() entry.title = str(scan) entry.date = utils.iso8601(scan.date) entry.command = scan.scanCmd entry.scan_number = NXfield(scan.scanNum) entry.comments = '\n'.join(scan.comments) entry.data = self.scan_NXdata(scan) # store the scan data entry.positioners = self.metadata_NXlog( scan.positioner, 'SPEC positioners (#P & #O lines)') if hasattr(scan, 'metadata') and len(scan.metadata) > 0: entry.metadata = self.metadata_NXlog( scan.metadata, 'SPEC metadata (UNICAT-style #H & #V lines)') if len(scan.G) > 0: entry.G = NXlog() desc = "SPEC geometry arrays, meanings defined by SPEC diffractometer support" # e.g.: SPECD/four.mac # http://certif.com/spec_manual/fourc_4_9.html entry.G.attrs['description'] = desc for item, value in scan.G.items(): entry.G[item] = NXfield(list(map(float, value.split()))) if scan.T != '': entry['counting_basis'] = NXfield( 'SPEC scan with constant counting time') entry['T'] = NXfield(float(scan.T)) entry['T'].units = 'seconds' entry[ 'T'].description = 'SPEC scan with constant counting time' elif scan.M != '': entry['counting_basis'] = NXfield( 'SPEC scan with constant monitor count') entry['M'] = NXfield(float(scan.M)) entry['M'].units = 'counts' entry[ 'M'].description = 'SPEC scan with constant monitor count' if scan.Q != '': entry['Q'] = NXfield(list(map(float, scan.Q))) entry['Q'].description = 'hkl at start of scan' root['scan_' + str(key)] = entry self.progress_bar.setValue(int(key)) self.update_progress() return root def scan_NXdata(self, scan): ''' return the scan data in an NXdata object ''' nxdata = NXdata() if len(scan.data) == 0: # what if no data? # since no data available, provide trivial, fake data # this keeps the NXdata base class compliant with the NeXus standard nxdata.attrs['description'] = 'SPEC scan has no data' nxdata['noSpecData_y'] = NXfield([0, 0]) # primary Y axis nxdata['noSpecData_x'] = NXfield([0, 0]) # primary X axis nxdata.nxsignal = nxdata['noSpecData_y'] nxdata.nxaxes = [ nxdata['noSpecData_x'], ] return nxdata nxdata.attrs['description'] = 'SPEC scan data' scan_type = scan.scanCmd.split()[0] if scan_type in ('mesh', 'hklmesh'): # hklmesh H 1.9 2.1 100 K 1.9 2.1 100 -800000 self.parser_mesh(nxdata, scan) elif scan_type in ('hscan', 'kscan', 'lscan', 'hklscan'): # hklscan 1.00133 1.00133 1.00133 1.00133 2.85 3.05 200 -400000 h_0, h_N, k_0, k_N, l_0, l_N = scan.scanCmd.split()[1:7] if h_0 != h_N: axis = 'H' elif k_0 != k_N: axis = 'K' elif l_0 != l_N: axis = 'L' else: axis = 'H' self.parser_1D_columns(nxdata, scan) nxdata.nxaxes = nxdata[axis] else: self.parser_1D_columns(nxdata, scan) # these locations suggested to NIAC, easier to parse than attached to dataset! # but these are already set by the `nxsignal` and `nxaxes` assignments #nxdata.attrs['signal'] = nxdata.nxsignal.nxname #nxdata.attrs['axes'] = ':'.join([obj.nxname for obj in nxdata.nxaxes]) return nxdata def parser_1D_columns(self, nxdata, scan): '''generic data parser for 1-D column data''' from spec2nexus import utils for column in scan.L: if column in scan.data: clean_name = utils.sanitize_name(nxdata, column) nxdata[clean_name] = NXfield(scan.data[column]) nxdata[clean_name].original_name = column signal = utils.sanitize_name(nxdata, scan.column_last) # primary Y axis axis = utils.sanitize_name(nxdata, scan.column_first) # primary X axis nxdata.nxsignal = nxdata[signal] nxdata.nxaxes = nxdata[axis] self.parser_mca_spectra(nxdata, scan, axis) def parser_mca_spectra(self, nxdata, scan, primary_axis_label): '''parse for optional MCA spectra''' if '_mca_' in scan.data: # check for it for mca_key, mca_data in scan.data['_mca_'].items(): key = "__" + mca_key nxdata[key] = NXfield(mca_data) nxdata[key].units = "counts" ch_key = key + "_channel" nxdata[ch_key] = NXfield(range(1, len(mca_data[0]) + 1)) nxdata[ch_key].units = 'channel' axes = (primary_axis_label, ch_key) nxdata[key].axes = ':'.join(axes) def parser_mesh(self, nxdata, scan): '''data parser for 2-D mesh and hklmesh''' # 2-D parser: http://www.certif.com/spec_help/mesh.html # mesh motor1 start1 end1 intervals1 motor2 start2 end2 intervals2 time # 2-D parser: http://www.certif.com/spec_help/hklmesh.html # hklmesh Q1 start1 end1 intervals1 Q2 start2 end2 intervals2 time # mesh: nexpy/examples/33id_spec.dat scan 22 (also has MCA, thus 3-D data) # hklmesh: nexpy/examples/33bm_spec.dat scan 17 (no MCA data) from spec2nexus import utils label1, start1, end1, intervals1, label2, start2, end2, intervals2, time = scan.scanCmd.split( )[1:] if label1 not in scan.data: label1 = scan.L[0] # mnemonic v. name if label2 not in scan.data: label2 = scan.L[1] # mnemonic v. name axis1 = scan.data.get(label1) axis2 = scan.data.get(label2) intervals1, intervals2 = int(intervals1), int(intervals2) start1, end1 = float(start1), float(end1) start2, end2 = float(start2), float(end2) time = float(time) if len(axis1) < intervals1: # stopped scan before second row started self.parser_1D_columns(nxdata, scan) # fallback support # TODO: what about the MCA data in this case? else: axis1 = axis1[0:intervals1 + 1] axis2 = [ axis2[row] for row in range(len(axis2)) if row % (intervals1 + 1) == 0 ] column_labels = scan.L column_labels.remove(label1) # special handling column_labels.remove(label2) # special handling if scan.scanCmd.startswith('hkl'): # find the reciprocal space axis held constant label3 = [ key for key in ('H', 'K', 'L') if key not in (label1, label2) ][0] axis3 = scan.data.get(label3)[0] nxdata[label3] = NXfield(axis3) column_labels.remove(label3) # already handled nxdata[label1] = NXfield(axis1) # 1-D array nxdata[label2] = NXfield(axis2) # 1-D array # build 2-D data objects (do not build label1, label2, [or label3] as 2-D objects) data_shape = [len(axis2), len(axis1)] for label in column_labels: axis = np.array(scan.data.get(label)) clean_name = utils.sanitize_name(nxdata, label) nxdata[clean_name] = NXfield( utils.reshape_data(axis, data_shape)) nxdata[clean_name].original_name = label signal_axis_label = utils.sanitize_name(nxdata, scan.column_last) nxdata.nxsignal = nxdata[signal_axis_label] nxdata.nxaxes = [nxdata[label2], nxdata[label1]] if '_mca_' in scan.data: # 3-D array # TODO: ?merge with parser_mca_spectra()? for mca_key, mca_data in scan.data['_mca_'].items(): key = "__" + mca_key spectra_lengths = list(map(len, mca_data)) num_channels = max(spectra_lengths) if num_channels != min(spectra_lengths): msg = 'MCA spectra have different lengths' msg += ' in scan #' + str(scan.scanNum) msg += ' in file ' + str(scan.specFile) raise ValueError(msg) data_shape += [ num_channels, ] mca = np.array(mca_data) nxdata[key] = NXfield(utils.reshape_data(mca, data_shape)) nxdata[key].units = "counts" try: # use MCA channel numbers as known at time of scan chan1 = scan.MCA['first_saved'] chanN = scan.MCA['last_saved'] channel_range = range(chan1, chanN + 1) except: # basic indices channel_range = range(1, num_channels + 1) ch_key = key + "_channel" nxdata[ch_key] = NXfield(channel_range) nxdata[ch_key].units = 'channel' axes = (label1, label2, ch_key) nxdata[key].axes = ':'.join(axes) def metadata_NXlog(self, spec_metadata, description): ''' return the specific metadata in an NXlog object ''' from spec2nexus import utils nxlog = NXlog() nxlog.attrs['description'] = description for subkey, value in spec_metadata.items(): clean_name = utils.sanitize_name(nxlog, subkey) nxlog[clean_name] = NXfield(value) nxlog[clean_name].original_name = subkey return nxlog
class Parser(object): '''parse the spec data file object''' def __init__(self, spec_data = None): ''':param obj spec_data: instance of :class:`spec2nexus.prjPySpec.SpecDataFile`''' self.SPECfile = spec_data self.progress_bar = spec_data.progress_bar self.update_progress = spec_data.update_progress def openFile(self, filename): '''open the SPEC file and get its data''' from spec2nexus.spec import SpecDataFile if os.path.exists(filename): self.SPECfile = SpecDataFile(filename) def toTree(self, scan_list=[]): ''' convert scans from chosen SPEC file into NXroot object and structure called from nexpy.readers.readspec.ImportDialog.get_data__prjPySpec() after clicking <Ok> in dialog Each scan in the range from self.scanmin to self.scanmax (inclusive) will be converted to a NXentry. Scan data will go in a NXdata where the signal=1 is the last column and the corresponding axes= is the first column. :param [int] scanlist :raises: ValueError is Min or Max scan number are not given properly ''' import spec2nexus from spec2nexus import utils # check that scan_list is valid if len(scan_list) == 0: return None if self.SPECfile is None: return None complete_scan_list = list(self.SPECfile.scans) for key in [str(s) for s in scan_list]: if key not in complete_scan_list: msg = 'scan ' + str(key) + ' was not found' raise ValueError(msg) root = NXroot() root.attrs['spec2nexus'] = str(spec2nexus.__version__) header0 = self.SPECfile.headers[0] root.attrs['SPEC_file'] = self.SPECfile.fileName root.attrs['SPEC_epoch'] = header0.epoch root.attrs['SPEC_date'] = utils.iso8601(header0.date) root.attrs['SPEC_comments'] = '\n'.join(header0.comments) try: c = header0.comments[0] user = c[c.find('User = '******'=')[1].strip() root.attrs['SPEC_user'] = user except: pass root.attrs['SPEC_num_headers'] = len(self.SPECfile.headers) self.progress_bar.setVisible(True) self.progress_bar.setRange(scan_list[0], scan_list[-1]) for key in [str(s) for s in scan_list]: scan = self.SPECfile.getScan(key) scan.interpret() entry = NXentry() entry.title = str(scan) entry.date = utils.iso8601(scan.date) entry.command = scan.scanCmd entry.scan_number = NXfield(scan.scanNum) entry.comments = '\n'.join(scan.comments) entry.data = self.scan_NXdata(scan) # store the scan data entry.positioners = self.metadata_NXlog(scan.positioner, 'SPEC positioners (#P & #O lines)') if hasattr(scan, 'metadata') and len(scan.metadata) > 0: entry.metadata = self.metadata_NXlog(scan.metadata, 'SPEC metadata (UNICAT-style #H & #V lines)') if len(scan.G) > 0: entry.G = NXlog() desc = "SPEC geometry arrays, meanings defined by SPEC diffractometer support" # e.g.: SPECD/four.mac # http://certif.com/spec_manual/fourc_4_9.html entry.G.attrs['description'] = desc for item, value in scan.G.items(): entry.G[item] = NXfield(list(map(float, value.split()))) if scan.T != '': entry['counting_basis'] = NXfield('SPEC scan with constant counting time') entry['T'] = NXfield(float(scan.T)) entry['T'].units = 'seconds' entry['T'].description = 'SPEC scan with constant counting time' elif scan.M != '': entry['counting_basis'] = NXfield('SPEC scan with constant monitor count') entry['M'] = NXfield(float(scan.M)) entry['M'].units = 'counts' entry['M'].description = 'SPEC scan with constant monitor count' if scan.Q != '': entry['Q'] = NXfield(list(map(float,scan.Q))) entry['Q'].description = 'hkl at start of scan' root['scan_' + str(key)] = entry self.progress_bar.setValue(int(key)) self.update_progress() return root def scan_NXdata(self, scan): ''' return the scan data in an NXdata object ''' nxdata = NXdata() if len(scan.data) == 0: # what if no data? # since no data available, provide trivial, fake data # this keeps the NXdata base class compliant with the NeXus standard nxdata.attrs['description'] = 'SPEC scan has no data' nxdata['noSpecData_y'] = NXfield([0, 0]) # primary Y axis nxdata['noSpecData_x'] = NXfield([0, 0]) # primary X axis nxdata.nxsignal = nxdata['noSpecData_y'] nxdata.nxaxes = [nxdata['noSpecData_x'], ] return nxdata nxdata.attrs['description'] = 'SPEC scan data' scan_type = scan.scanCmd.split()[0] if scan_type in ('mesh', 'hklmesh'): # hklmesh H 1.9 2.1 100 K 1.9 2.1 100 -800000 self.parser_mesh(nxdata, scan) elif scan_type in ('hscan', 'kscan', 'lscan', 'hklscan'): # hklscan 1.00133 1.00133 1.00133 1.00133 2.85 3.05 200 -400000 h_0, h_N, k_0, k_N, l_0, l_N = scan.scanCmd.split()[1:7] if h_0 != h_N: axis = 'H' elif k_0 != k_N: axis = 'K' elif l_0 != l_N: axis = 'L' else: axis = 'H' self.parser_1D_columns(nxdata, scan) nxdata.nxaxes = nxdata[axis] else: self.parser_1D_columns(nxdata, scan) # these locations suggested to NIAC, easier to parse than attached to dataset! # but these are already set by the `nxsignal` and `nxaxes` assignments #nxdata.attrs['signal'] = nxdata.nxsignal.nxname #nxdata.attrs['axes'] = ':'.join([obj.nxname for obj in nxdata.nxaxes]) return nxdata def parser_1D_columns(self, nxdata, scan): '''generic data parser for 1-D column data''' from spec2nexus import utils for column in scan.L: if column in scan.data: clean_name = utils.sanitize_name(nxdata, column) nxdata[clean_name] = NXfield(scan.data[column]) nxdata[clean_name].original_name = column signal = utils.sanitize_name(nxdata, scan.column_last) # primary Y axis axis = utils.sanitize_name(nxdata, scan.column_first) # primary X axis nxdata.nxsignal = nxdata[signal] nxdata.nxaxes = nxdata[axis] self.parser_mca_spectra(nxdata, scan, axis) def parser_mca_spectra(self, nxdata, scan, primary_axis_label): '''parse for optional MCA spectra''' if '_mca_' in scan.data: # check for it for mca_key, mca_data in scan.data['_mca_'].items(): key = "__" + mca_key nxdata[key] = NXfield(mca_data) nxdata[key].units = "counts" ch_key = key + "_channel" nxdata[ch_key] = NXfield(range(1, len(mca_data[0])+1)) nxdata[ch_key].units = 'channel' axes = (primary_axis_label, ch_key) nxdata[key].axes = ':'.join( axes ) def parser_mesh(self, nxdata, scan): '''data parser for 2-D mesh and hklmesh''' # 2-D parser: http://www.certif.com/spec_help/mesh.html # mesh motor1 start1 end1 intervals1 motor2 start2 end2 intervals2 time # 2-D parser: http://www.certif.com/spec_help/hklmesh.html # hklmesh Q1 start1 end1 intervals1 Q2 start2 end2 intervals2 time # mesh: nexpy/examples/33id_spec.dat scan 22 (also has MCA, thus 3-D data) # hklmesh: nexpy/examples/33bm_spec.dat scan 17 (no MCA data) from spec2nexus import utils label1, start1, end1, intervals1, label2, start2, end2, intervals2, time = scan.scanCmd.split()[1:] if label1 not in scan.data: label1 = scan.L[0] # mnemonic v. name if label2 not in scan.data: label2 = scan.L[1] # mnemonic v. name axis1 = scan.data.get(label1) axis2 = scan.data.get(label2) intervals1, intervals2 = int(intervals1), int(intervals2) start1, end1 = float(start1), float(end1) start2, end2 = float(start2), float(end2) time = float(time) if len(axis1) < intervals1: # stopped scan before second row started self.parser_1D_columns(nxdata, scan) # fallback support # TODO: what about the MCA data in this case? else: axis1 = axis1[0:intervals1+1] axis2 = [axis2[row] for row in range(len(axis2)) if row % (intervals1+1) == 0] column_labels = scan.L column_labels.remove(label1) # special handling column_labels.remove(label2) # special handling if scan.scanCmd.startswith('hkl'): # find the reciprocal space axis held constant label3 = [key for key in ('H', 'K', 'L') if key not in (label1, label2)][0] axis3 = scan.data.get(label3)[0] nxdata[label3] = NXfield(axis3) column_labels.remove(label3) # already handled nxdata[label1] = NXfield(axis1) # 1-D array nxdata[label2] = NXfield(axis2) # 1-D array # build 2-D data objects (do not build label1, label2, [or label3] as 2-D objects) data_shape = [len(axis2), len(axis1)] for label in column_labels: axis = np.array( scan.data.get(label) ) clean_name = utils.sanitize_name(nxdata, label) nxdata[clean_name] = NXfield(utils.reshape_data(axis, data_shape)) nxdata[clean_name].original_name = label signal_axis_label = utils.sanitize_name(nxdata, scan.column_last) nxdata.nxsignal = nxdata[signal_axis_label] nxdata.nxaxes = [nxdata[label2], nxdata[label1]] if '_mca_' in scan.data: # 3-D array # TODO: ?merge with parser_mca_spectra()? for mca_key, mca_data in scan.data['_mca_'].items(): key = "__" + mca_key spectra_lengths = list(map(len, mca_data)) num_channels = max(spectra_lengths) if num_channels != min(spectra_lengths): msg = 'MCA spectra have different lengths' msg += ' in scan #' + str(scan.scanNum) msg += ' in file ' + str(scan.specFile) raise ValueError(msg) data_shape += [num_channels, ] mca = np.array(mca_data) nxdata[key] = NXfield(utils.reshape_data(mca, data_shape)) nxdata[key].units = "counts" try: # use MCA channel numbers as known at time of scan chan1 = scan.MCA['first_saved'] chanN = scan.MCA['last_saved'] channel_range = range(chan1, chanN+1) except: # basic indices channel_range = range(1, num_channels+1) ch_key = key + "_channel" nxdata[ch_key] = NXfield(channel_range) nxdata[ch_key].units = 'channel' axes = (label1, label2, ch_key) nxdata[key].axes = ':'.join( axes ) def metadata_NXlog(self, spec_metadata, description): ''' return the specific metadata in an NXlog object ''' from spec2nexus import utils nxlog = NXlog() nxlog.attrs['description'] = description for subkey, value in spec_metadata.items(): clean_name = utils.sanitize_name(nxlog, subkey) nxlog[clean_name] = NXfield(value) nxlog[clean_name].original_name = subkey return nxlog
from mpl_toolkits.mplot3d import Axes3D, axes3d import numpy as np import matplotlib.pyplot as plt from spec2nexus.spec import SpecDataFile from PyQt5.QtWidgets import * import pylab as plab from matplotlib.backends.backend_qt5 import NavigationToolbar2QT as NavigationToolbar from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas # Loading the data. data = np.loadtxt("C:\\Users\\escal\\Downloads\\PVvalue.259") # Loading Spec information for scan#: 259 # ======================================== specFile = SpecDataFile("C:\\Users\\escal\\Downloads\\pmnpt_1.spec") l = specFile.scans["259"].data["L"] ######################################################################################################################## # Plotting the data in 3D ######################################################################################################################## fig1 = plt.figure() ax = Axes3D(fig1) ax.set_ylabel("Data") ax.set_xlabel("Points") ax.set_zlabel("L") x = range(0, 64) # This will have to be replaced by voltage for i in range(0, 3721): z = np.full(64, l[i]) y = data[i] ax.plot(x, y, zs=z)
class ImportDialog(BaseImportDialog): """Dialog to import SPEC Scans""" def __init__(self, parent=None): super(ImportDialog, self).__init__(parent) self.accepted = False from nexpy.gui.consoleapp import _mainwindow self.default_directory = _mainwindow.default_directory self.import_file = None # must set in self.get_data() self.spec = None # progress bar is updated via calls to pdate_progress() self.progress_bar = QtGui.QProgressBar() self.progress_bar.setVisible(False) status_layout = QtGui.QHBoxLayout() status_layout.addWidget(self.progress_bar) status_layout.addStretch() status_layout.addWidget(self.close_buttons()) self.layout = QtGui.QVBoxLayout() self.layout.addLayout(self.filebox()) self.layout.addLayout(self.scanbox()) self.layout.addLayout(status_layout) self.setLayout(self.layout) self.setWindowTitle("Import " + str(filetype)) def scanbox(self): """create widgets for specifying scan range to import""" scanminlabel = QtGui.QLabel("Min. Scan") self.scanmin = QtGui.QLineEdit() self.scanmin.setFixedWidth(100) self.scanmin.setAlignment(QtCore.Qt.AlignRight) scanmaxlabel = QtGui.QLabel("Max. Scan") self.scanmax = QtGui.QLineEdit() self.scanmax.setFixedWidth(100) self.scanmax.setAlignment(QtCore.Qt.AlignRight) scanbox = QtGui.QHBoxLayout() scanbox.addWidget(scanminlabel) scanbox.addWidget(self.scanmin) scanbox.addWidget(scanmaxlabel) scanbox.addWidget(self.scanmax) return scanbox def choose_file(self): """ Opens file dialog, set file text box to the chosen path """ from spec2nexus.spec import SpecDataFile dirname = self.get_default_directory(self.filename.text()) filename = getOpenFileName(self, "Open file", dirname) if os.path.exists(filename): self.filename.setText(str(filename)) self.spec = SpecDataFile(self.get_filename()) self.set_default_directory(os.path.dirname(filename)) scan_min = self.spec.getMinScanNumber() self.scanmin.setText(str(scan_min)) scan_max = self.spec.getMaxScanNumber() self.scanmax.setText(str(scan_max)) def get_data(self): """read the data and return either :class:`NXroot` or :class:`NXentry`""" self.import_file = self.get_filename() if not os.path.exists(self.import_file): return None if self.spec is None: return None scan_min = int(self.scanmin.text()) scan_max = int(self.scanmax.text()) all_scans = self.spec.getScanNumbers() scans = [s for s in all_scans if scan_min <= s <= scan_max] self.spec.progress_bar = self.progress_bar self.spec.update_progress = self.update_progress return Parser(self.spec).toTree(scans)
def openFile(self, filename): """open the SPEC file and get its data""" from spec2nexus.prjPySpec import SpecDataFile if os.path.exists(filename): self.SPECfile = SpecDataFile(filename)
class Parser(object): """parse the spec data file object""" def __init__(self, spec_data=None): """:param obj spec_data: instance of :class:`spec2nexus.prjPySpec.SpecDataFile`""" self.SPECfile = spec_data self.progress_bar = spec_data.progress_bar self.update_progress = spec_data.update_progress def openFile(self, filename): """open the SPEC file and get its data""" from spec2nexus.prjPySpec import SpecDataFile if os.path.exists(filename): self.SPECfile = SpecDataFile(filename) def toTree(self, scan_list=[]): """ convert scans from chosen SPEC file into NXroot object and structure called from nexpy.readers.readspec.ImportDialog.get_data__prjPySpec() after clicking <Ok> in dialog Each scan in the range from self.scanmin to self.scanmax (inclusive) will be converted to a NXentry. Scan data will go in a NXdata where the signal=1 is the last column and the corresponding axes= is the first column. :param [int] scanlist :raises: ValueError is Min or Max scan number are not given properly """ import spec2nexus from spec2nexus import utils # check that scan_list is valid if len(scan_list) == 0: return None if self.SPECfile is None: return None complete_scan_list = self.SPECfile.scans.keys() for key in scan_list: if key not in complete_scan_list: msg = "scan " + str(key) + " was not found" raise ValueError, msg root = NXroot() root.attrs["spec2nexus"] = str(spec2nexus.__version__) header0 = self.SPECfile.headers[0] root.attrs["SPEC_file"] = self.SPECfile.fileName root.attrs["SPEC_epoch"] = header0.epoch root.attrs["SPEC_date"] = utils.iso8601(header0.date) root.attrs["SPEC_comments"] = "\n".join(header0.comments) try: c = header0.comments[0] user = c[c.find("User = "******"=")[1].strip() root.attrs["SPEC_user"] = user except: pass root.attrs["SPEC_num_headers"] = len(self.SPECfile.headers) self.progress_bar.setVisible(True) self.progress_bar.setRange(scan_list[0], scan_list[-1]) for key in scan_list: scan = self.SPECfile.getScan(key) scan.interpret() entry = NXentry() entry.title = str(scan) entry.date = utils.iso8601(scan.date) entry.command = scan.scanCmd entry.scan_number = NXfield(scan.scanNum) entry.comments = "\n".join(scan.comments) entry.data = self.scan_NXdata(scan) # store the scan data entry.positioners = self.metadata_NXlog(scan.positioner, "SPEC positioners (#P & #O lines)") if hasattr(scan, "metadata") and len(scan.metadata) > 0: entry.metadata = self.metadata_NXlog(scan.metadata, "SPEC metadata (UNICAT-style #H & #V lines)") if len(scan.G) > 0: entry.G = NXlog() desc = "SPEC geometry arrays, meanings defined by SPEC diffractometer support" # e.g.: SPECD/four.mac # http://certif.com/spec_manual/fourc_4_9.html entry.G.attrs["description"] = desc for item, value in scan.G.items(): entry.G[item] = NXfield(map(float, value.split())) if scan.T != "": entry["counting_basis"] = NXfield("SPEC scan with constant counting time") entry["T"] = NXfield(float(scan.T)) entry["T"].units = "seconds" entry["T"].description = "SPEC scan with constant counting time" elif scan.M != "": entry["counting_basis"] = NXfield("SPEC scan with constant monitor count") entry["M"] = NXfield(float(scan.M)) entry["M"].units = "counts" entry["M"].description = "SPEC scan with constant monitor count" if scan.Q != "": entry["Q"] = NXfield(map(float, scan.Q)) entry["Q"].description = "hkl at start of scan" root["scan_" + str(key)] = entry self.progress_bar.setValue(key) self.update_progress() return root def scan_NXdata(self, scan): """ return the scan data in an NXdata object """ nxdata = NXdata() if len(scan.data) == 0: # what if no data? # since no data available, provide trivial, fake data # this keeps the NXdata base class compliant with the NeXus standard nxdata.attrs["description"] = "SPEC scan has no data" nxdata["noSpecData_y"] = NXfield([0, 0]) # primary Y axis nxdata["noSpecData_x"] = NXfield([0, 0]) # primary X axis nxdata.nxsignal = nxdata["noSpecData_y"] nxdata.nxaxes = [nxdata["noSpecData_x"]] return nxdata nxdata.attrs["description"] = "SPEC scan data" scan_type = scan.scanCmd.split()[0] if scan_type in ("mesh", "hklmesh"): # hklmesh H 1.9 2.1 100 K 1.9 2.1 100 -800000 self.parser_mesh(nxdata, scan) elif scan_type in ("hscan", "kscan", "lscan", "hklscan"): # hklscan 1.00133 1.00133 1.00133 1.00133 2.85 3.05 200 -400000 h_0, h_N, k_0, k_N, l_0, l_N = scan.scanCmd.split()[1:7] if h_0 != h_N: axis = "H" elif k_0 != k_N: axis = "K" elif l_0 != l_N: axis = "L" else: axis = "H" self.parser_1D_columns(nxdata, scan) nxdata.nxaxes = nxdata[axis] else: self.parser_1D_columns(nxdata, scan) # these locations suggested to NIAC, easier to parse than attached to dataset! nxdata.attrs["signal"] = nxdata.nxsignal.nxname nxdata.attrs["axes"] = ":".join([obj.nxname for obj in nxdata.nxaxes]) return nxdata def parser_1D_columns(self, nxdata, scan): """generic data parser for 1-D column data""" from spec2nexus import utils for column in scan.L: if column in scan.data: clean_name = utils.sanitize_name(nxdata, column) nxdata[clean_name] = NXfield(scan.data[column]) nxdata[clean_name].original_name = column signal = utils.sanitize_name(nxdata, scan.column_last) # primary Y axis axis = utils.sanitize_name(nxdata, scan.column_first) # primary X axis nxdata.nxsignal = nxdata[signal] nxdata.nxaxes = nxdata[axis] self.parser_mca_spectra(nxdata, scan, axis) def parser_mca_spectra(self, nxdata, scan, primary_axis_label): """parse for optional MCA spectra""" if "_mca_" in scan.data: # check for it nxdata.mca__spectrum_ = NXfield(scan.data["_mca_"]) nxdata.mca__spectrum_channel = NXfield(range(1, len(scan.data["_mca_"][0]) + 1)) nxdata.mca__spectrum_channel.units = "channel" axes = (primary_axis_label, "mca__spectrum_channel") nxdata.mca__spectrum_.axes = ":".join(axes) def parser_mesh(self, nxdata, scan): """data parser for 2-D mesh and hklmesh""" # 2-D parser: http://www.certif.com/spec_help/mesh.html # mesh motor1 start1 end1 intervals1 motor2 start2 end2 intervals2 time # 2-D parser: http://www.certif.com/spec_help/hklmesh.html # hklmesh Q1 start1 end1 intervals1 Q2 start2 end2 intervals2 time # mesh: nexpy/examples/33id_spec.dat scan 22 (also has MCA, thus 3-D data) # hklmesh: nexpy/examples/33bm_spec.dat scan 17 (no MCA data) from spec2nexus import utils label1, start1, end1, intervals1, label2, start2, end2, intervals2, time = scan.scanCmd.split()[1:] if label1 not in scan.data: label1 = scan.L[0] # mnemonic v. name if label2 not in scan.data: label2 = scan.L[1] # mnemonic v. name axis1 = scan.data.get(label1) axis2 = scan.data.get(label2) intervals1, intervals2 = map(int, (intervals1, intervals2)) start1, end1, start2, end2, time = map(float, (start1, end1, start2, end2, time)) if len(axis1) < intervals1: # stopped scan before second row started self.parser_1D_columns(nxdata, scan) # fallback support # TODO: what about the MCA data in this case? else: axis1 = axis1[0 : intervals1 + 1] axis2 = [axis2[row] for row in range(len(axis2)) if row % (intervals1 + 1) == 0] column_labels = scan.L column_labels.remove(label1) # special handling column_labels.remove(label2) # special handling if scan.scanCmd.startswith("hkl"): # find the reciprocal space axis held constant label3 = [key for key in ("H", "K", "L") if key not in (label1, label2)][0] axis3 = scan.data.get(label3)[0] nxdata[label3] = NXfield(axis3) column_labels.remove(label3) # already handled nxdata[label1] = NXfield(axis1) # 1-D array nxdata[label2] = NXfield(axis2) # 1-D array # build 2-D data objects (do not build label1, label2, [or label3] as 2-D objects) data_shape = [len(axis2), len(axis1)] for label in column_labels: axis = np.array(scan.data.get(label)) clean_name = utils.sanitize_name(nxdata, label) nxdata[clean_name] = NXfield(utils.reshape_data(axis, data_shape)) nxdata[clean_name].original_name = label signal_axis_label = utils.sanitize_name(nxdata, scan.column_last) nxdata.nxsignal = nxdata[signal_axis_label] nxdata.nxaxes = [nxdata[label2], nxdata[label1]] if "_mca_" in scan.data: # 3-D array # TODO: ?merge with parser_mca_spectra()? _num_spectra = len(scan.data["_mca_"]) spectra_lengths = map(len, scan.data["_mca_"]) num_channels = max(spectra_lengths) if num_channels != min(spectra_lengths): msg = "MCA spectra have different lengths" msg += " in scan #" + str(scan.scanNum) msg += " in file " + str(scan.specFile) raise ValueError(msg) data_shape += [num_channels] mca = np.array(scan.data["_mca_"]) nxdata.mca__spectrum_ = NXfield(utils.reshape_data(mca, data_shape)) try: # use MCA channel numbers as known at time of scan chan1 = scan.MCA["first_saved"] chanN = scan.MCA["last_saved"] channel_range = range(chan1, chanN + 1) except: # basic indices channel_range = range(1, num_channels + 1) nxdata.mca__spectrum_channel = NXfield(channel_range) nxdata.mca__spectrum_channel.units = "channel" axes = (label1, label2, "mca__spectrum_channel") nxdata.mca__spectrum_.axes = ":".join(axes) def metadata_NXlog(self, spec_metadata, description): """ return the specific metadata in an NXlog object """ from spec2nexus import utils nxlog = NXlog() nxlog.attrs["description"] = description for subkey, value in spec_metadata.items(): clean_name = utils.sanitize_name(nxlog, subkey) nxlog[clean_name] = NXfield(value) nxlog[clean_name].original_name = subkey return nxlog