def FitProcessSpectrum(self, pymca_config, spectrum): advancedFit = ClassMcaTheory.McaTheory(config=pymca_config) advancedFit.enableOptimizedLinearFit() mfTool = ConcentrationsTool(pymca_config) tconf = mfTool.configure() advancedFit.config['fit']['use_limit'] = 1 advancedFit.setData(y=spectrum) advancedFit.estimate() fitresult, tmpresult = advancedFit.startfit(digest=1) tmpresult = advancedFit.imagingDigestResult() temp = {} temp['fitresult'] = fitresult temp['result'] = tmpresult for bcts, pk in zip(self.BckndCounts, self.peaks_quant): tmpresult[pk]['fitarea'] -= bcts temp['result']['config'] = advancedFit.config tconf.update(advancedFit.configure()['concentrations']) conc = mfTool.processFitResult(config=tconf, fitresult=temp, elementsfrommatrix=False, fluorates=advancedFit._fluoRates) calc_mf = numpy.float32( [conc['mass fraction'][pk] for pk in self.peaks_quant]) return calc_mf, tmpresult
def __init__(self): self.mcafit = ClassMcaTheory.McaTheory() self.ctool = ConcentrationsTool.ConcentrationsTool() self.app = None
def testTrainingDataFit(self): from PyMca5.PyMcaIO import specfilewrapper as specfile from PyMca5.PyMcaPhysics.xrf import ClassMcaTheory from PyMca5.PyMcaPhysics.xrf import ConcentrationsTool from PyMca5.PyMcaIO import ConfigDict trainingDataFile = os.path.join(self.dataDir, "XRFSpectrum.mca") self.assertTrue(os.path.isfile(trainingDataFile), "File %s is not an actual file" % trainingDataFile) sf = specfile.Specfile(trainingDataFile) self.assertTrue( len(sf) == 2, "Training data not interpreted as two scans") self.assertTrue(sf[0].nbmca() == 0, "Training data 1st scan should contain no MCAs") self.assertTrue(sf[1].nbmca() == 1, "Training data 1st scan should contain no MCAs") y = mcaData = sf[1].mca(1) sf = None # perform the actual XRF analysis configuration = ConfigDict.ConfigDict() configuration.readfp(StringIO(cfg)) mcaFit = ClassMcaTheory.ClassMcaTheory() configuration = mcaFit.configure(configuration) x = numpy.arange(y.size).astype(numpy.float) mcaFit.setData(x, y, xmin=configuration["fit"]["xmin"], xmax=configuration["fit"]["xmax"]) mcaFit.estimate() fitResult, result = mcaFit.startFit(digest=1) # fit is already done, calculate the concentrations concentrationsConfiguration = configuration["concentrations"] cTool = ConcentrationsTool.ConcentrationsTool() cToolConfiguration = cTool.configure() cToolConfiguration.update(configuration['concentrations']) # make sure we are using Co as internal standard cToolConfiguration["usematrix"] = 1 cToolConfiguration["reference"] = "Co" concentrationsResult, addInfo = cTool.processFitResult( \ config=cToolConfiguration, fitresult={"result":result}, elementsfrommatrix=False, fluorates = mcaFit._fluoRates, addinfo=True) referenceElement = addInfo['ReferenceElement'] referenceTransitions = addInfo['ReferenceTransitions'] self.assertTrue( referenceElement == "Co", "referenceElement is <%s> instead of <Co>" % referenceElement) cobalt = concentrationsResult["mass fraction"]["Co K"] self.assertTrue( abs(cobalt - 0.0005) < 1.0E-7, "Wrong Co concentration %f expected 0.0005" % cobalt) # we should get the same result with internal parameters cTool = ConcentrationsTool.ConcentrationsTool() cToolConfiguration = cTool.configure() cToolConfiguration.update(configuration['concentrations']) # make sure we are not using an internal standard cToolConfiguration['usematrix'] = 0 cToolConfiguration['flux'] = addInfo["Flux"] cToolConfiguration['time'] = addInfo["Time"] cToolConfiguration['area'] = addInfo["DetectorArea"] cToolConfiguration['distance'] = addInfo["DetectorDistance"] concentrationsResult2, addInfo = cTool.processFitResult( \ config=cToolConfiguration, fitresult={"result":result}, elementsfrommatrix=False, fluorates = mcaFit._fluoRates, addinfo=True) referenceElement = addInfo['ReferenceElement'] referenceTransitions = addInfo['ReferenceTransitions'] self.assertTrue( referenceElement in ["None", "", None], "referenceElement is <%s> instead of <None>" % referenceElement) for key in concentrationsResult["mass fraction"]: internal = concentrationsResult["mass fraction"][key] fp = concentrationsResult2["mass fraction"][key] delta = 100 * (abs(internal - fp) / internal) self.assertTrue( delta < 1.0e-5, "Error for <%s> concentration %g != %g" % (key, internal, fp))
def testStainlessSteelDataFit(self): from PyMca5.PyMcaIO import specfilewrapper as specfile from PyMca5.PyMcaPhysics.xrf import ClassMcaTheory from PyMca5.PyMcaPhysics.xrf import ConcentrationsTool from PyMca5.PyMcaIO import ConfigDict # read the data dataFile = os.path.join(self.dataDir, "Steel.spe") self.assertTrue(os.path.isfile(dataFile), "File %s is not an actual file" % dataFile) sf = specfile.Specfile(dataFile) self.assertTrue(len(sf) == 1, "File %s cannot be read" % dataFile) self.assertTrue(sf[0].nbmca() == 1, "Spe file should contain MCA data") y = counts = sf[0].mca(1) x = channels = numpy.arange(y.size).astype(numpy.float) sf = None # read the fit configuration configFile = os.path.join(self.dataDir, "Steel.cfg") self.assertTrue(os.path.isfile(configFile), "File %s is not an actual file" % configFile) configuration = ConfigDict.ConfigDict() configuration.read(configFile) # configure the fit # make sure no secondary excitations are used configuration["concentrations"]["usemultilayersecondary"] = 0 mcaFit = ClassMcaTheory.ClassMcaTheory() configuration = mcaFit.configure(configuration) mcaFit.setData(x, y, xmin=configuration["fit"]["xmin"], xmax=configuration["fit"]["xmax"]) mcaFit.estimate() fitResult, result = mcaFit.startFit(digest=1) # concentrations # fit is already done, calculate the concentrations concentrationsConfiguration = configuration["concentrations"] cTool = ConcentrationsTool.ConcentrationsTool() cToolConfiguration = cTool.configure() cToolConfiguration.update(configuration['concentrations']) # make sure we are using Fe as internal standard matrix = configuration["attenuators"]["Matrix"] self.assertTrue( matrix[1] == "SRM_1155", "Invalid matrix. Expected <SRM_1155> got <%s>" % matrix[1]) cToolConfiguration["usematrix"] = 1 cToolConfiguration["reference"] = "Fe" concentrationsResult, addInfo = cTool.processFitResult( \ config=cToolConfiguration, fitresult={"result":result}, elementsfrommatrix=False, fluorates = mcaFit._fluoRates, addinfo=True) referenceElement = addInfo['ReferenceElement'] referenceTransitions = addInfo['ReferenceTransitions'] self.assertTrue( referenceElement == "Fe", "referenceElement is <%s> instead of <Fe>" % referenceElement) # check the Fe concentration is 0.65 +/ 5 % self.assertTrue( \ abs(concentrationsResult["mass fraction"]["Fe Ka"] - 0.65) < 0.03, "Invalid Fe Concentration") # check the Cr concentration is overestimated (more than 30 %) % testValue = concentrationsResult["mass fraction"]["Cr K"] self.assertTrue( testValue > 0.30, "Expected Cr concentration above 0.30 got %.3f" % testValue) # chek the sum of concentration of main components is above 1 # because of neglecting higher order excitations elements = ["Cr K", "V K", "Mn K", "Fe Ka", "Ni K"] total = 0.0 for element in elements: total += concentrationsResult["mass fraction"][element] self.assertTrue( total > 1, "Sum of concentrations should be above 1 got %.3f" % total) # correct for tertiary excitation without a new fit cToolConfiguration["usemultilayersecondary"] = 2 concentrationsResult, addInfo = cTool.processFitResult( \ config=cToolConfiguration, fitresult={"result":result}, elementsfrommatrix=False, fluorates = mcaFit._fluoRates, addinfo=True) # check the Fe concentration is 0.65 +/ 5 % self.assertTrue( \ abs(concentrationsResult["mass fraction"]["Fe Ka"] - 0.65) < 0.03, "Invalid Fe Concentration Using Tertiary Excitation") # chek the sum of concentration of main components is above 1 elements = ["Cr K", "Mn K", "Fe Ka", "Ni K"] total = 0.0 for element in elements: total += concentrationsResult["mass fraction"][element] self.assertTrue( total < 1, "Sum of concentrations should be below 1 got %.3f" % total) # check the Cr concentration is not overestimated (more than 30 %) % testValue = concentrationsResult["mass fraction"]["Cr K"] self.assertTrue( (testValue > 0.18) and (testValue < 0.20), "Expected Cr between 0.18 and 0.20 got %.3f" % testValue) # perform the fit already accounting for tertiary excitation # in order to get the good fundamental parameters configuration["concentrations"]['usematrix'] = 1 configuration["concentrations"]["usemultilayersecondary"] = 2 mcaFit.setConfiguration(configuration) mcaFit.setData(x, y, xmin=configuration["fit"]["xmin"], xmax=configuration["fit"]["xmax"]) mcaFit.estimate() fitResult, result = mcaFit.startFit(digest=1) # concentrations # fit is already done, calculate the concentrations concentrationsConfiguration = configuration["concentrations"] cTool = ConcentrationsTool.ConcentrationsTool() cToolConfiguration = cTool.configure() cToolConfiguration.update(configuration['concentrations']) matrix = configuration["attenuators"]["Matrix"] self.assertTrue( matrix[1] == "SRM_1155", "Invalid matrix. Expected <SRM_1155> got <%s>" % matrix[1]) cToolConfiguration["usematrix"] = 1 cToolConfiguration["reference"] = "Fe" concentrationsResult, addInfo = cTool.processFitResult( \ config=cToolConfiguration, fitresult={"result":result}, elementsfrommatrix=False, fluorates = mcaFit._fluoRates, addinfo=True) # make sure we are not using an internal standard # repeat everything using a single layer strategy configuration["concentrations"]['usematrix'] = 0 configuration["concentrations"]['flux'] = addInfo["Flux"] configuration["concentrations"]['time'] = addInfo["Time"] configuration["concentrations"]['area'] = addInfo["DetectorArea"] configuration["concentrations"]['distance'] = \ addInfo["DetectorDistance"] configuration["concentrations"]["usemultilayersecondary"] = 2 # setup the strategy starting with Fe as matrix matrix[1] = "Fe" configuration["attenuators"]["Matrix"] = matrix configuration["fit"]["strategyflag"] = 1 configuration["fit"]["strategy"] = "SingleLayerStrategy" configuration["SingleLayerStrategy"] = {} configuration["SingleLayerStrategy"]["layer"] = "Auto" configuration["SingleLayerStrategy"]["iterations"] = 3 configuration["SingleLayerStrategy"]["completer"] = "-" configuration["SingleLayerStrategy"]["flags"] = [ 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 ] configuration["SingleLayerStrategy"]["peaks"] = [ "Cr K", "Mn K", "Fe Ka", "Ni K", "-", "-", "-", "-", "-", "-" ] configuration["SingleLayerStrategy"]["materials"] = [ "Cr", "Mn", "Fe", "Ni", "-", "-", "-", "-", "-" ] mcaFit = ClassMcaTheory.ClassMcaTheory() configuration = mcaFit.configure(configuration) mcaFit.setData(x, y, xmin=configuration["fit"]["xmin"], xmax=configuration["fit"]["xmax"]) mcaFit.estimate() fitResult, result = mcaFit.startFit(digest=1) # concentrations # fit is already done, calculate the concentrations concentrationsConfiguration = configuration["concentrations"] cTool = ConcentrationsTool.ConcentrationsTool() cToolConfiguration = cTool.configure() cToolConfiguration.update(configuration['concentrations']) concentrationsResult2, addInfo = cTool.processFitResult( \ config=cToolConfiguration, fitresult={"result":result}, elementsfrommatrix=False, fluorates = mcaFit._fluoRates, addinfo=True) # chek the sum of concentration of main components is above 1 elements = ["Cr K", "Mn K", "Fe Ka", "Ni K"] total = 0.0 for element in elements: if element == "Cr K": tolerance = 6 # 6 % else: tolerance = 5 # 5 % previous = concentrationsResult["mass fraction"][element] current = concentrationsResult2["mass fraction"][element] delta = 100 * (abs(previous - current) / previous) self.assertTrue(delta < tolerance, "Strategy: Element %s discrepancy too large %.1f %%" % \ (element.split()[0], delta))
def PerformFit( filelist, cfgfile, energies, mlines={}, norm=None, fast=False, addhigh=0, prog=None, plot=False, ): """Fit XRF spectra in batch with changing primary beam energy. Args: filelist(list(str)|np.array): spectra to fit cfgfile(str): configuration file to use energies(np.array): primary beam energies mlines(Optional(dict)): elements (keys) which M line group must be replaced by some M subgroups (values) norm(Optional(np.array)): normalization array fast(Optional(bool)): fast fitting (linear) addhigh(Optional(number)): add higher energy prog(Optional(timing.ProgessLogger)): progress object plot(Optional(bool)) Returns: dict: {label:nenergies x nfiles,...} """ # Load data # Each spectrum (each row) in 1 edf file is acquired at a different energy if isinstance(filelist, list): dataStack = EDFStack.EDFStack(filelist, dtype=np.float32).data else: dataStack = filelist nfiles, nenergies, nchannels = dataStack.shape # MCA channels xmin = 0 xmax = nchannels - 1 x = np.arange(nchannels, dtype=np.float32) # Energies if hasattr(energies, "__iter__"): if len(energies) == 1: energies = [energies[0]] * nenergies elif len(energies) != nenergies: raise ValueError( "Expected {} energies ({} given)".format(nenergies, len(energies)) ) else: energies = [energies] * nenergies # Normalization if norm is None: norm = [1] * nenergies else: if hasattr(norm, "__iter__"): if len(norm) == 1: norm = [norm[0]] * nenergies elif len(norm) != nenergies: raise ValueError( "Expected {} normalization values ({} given)".format( nenergies, len(norm) ) ) else: norm = [norm] * nenergies # Prepare plot if plot: fig, ax = plt.subplots() # Prepare fit # ClassMcaTheory.DEBUG = 1 mcafit = ClassMcaTheory.McaTheory() try: mcafit.useFisxEscape(True) except: pass if fast: mcafit.enableOptimizedLinearFit() else: mcafit.disableOptimizedLinearFit() cfg = mcafit.configure(ReadPyMcaConfigFile(cfgfile)) # Fit at each energy if prog is not None: prog.setnfine(nenergies * nfiles) ret = {} for j in range(nenergies): # Prepare fit with this energy AdaptPyMcaConfig(cfg, energies[j], mlines=mlines, fast=fast, addhigh=addhigh) mcafit.configure(cfg) # Fit all spectra with this energy for i in range(nfiles): # Data to fit y = dataStack[i, j, :].flatten() mcafit.setData(x, y, xmin=xmin, xmax=xmax) # Initial parameter estimates mcafit.estimate() # Fit fitresult = mcafit.startfit(digest=0) # Extract result if plot: mcafitresult = mcafit.digestresult() ax.cla() if ( plot == 2 or not any(np.isfinite(np.log(mcafitresult["ydata"]))) or not any(mcafitresult["ydata"] > 0) ): ax.plot(mcafitresult["energy"], mcafitresult["ydata"]) ax.plot(mcafitresult["energy"], mcafitresult["yfit"], color="red") else: ax.semilogy(mcafitresult["energy"], mcafitresult["ydata"]) ax.semilogy( mcafitresult["energy"], mcafitresult["yfit"], color="red" ) ax.set_ylim( ymin=np.nanmin( mcafitresult["ydata"][np.nonzero(mcafitresult["ydata"])] ) ) ax.set_title("Primary energy: {} keV".format(energies[j])) ax.set_xlabel("Energy (keV)") ax.set_ylabel("Intensity (cts)") plt.pause(0.0001) else: mcafitresult = mcafit.imagingDigestResult() # Store result for k in mcafitresult["groups"]: if k not in ret: ret[k] = np.zeros( (nenergies, nfiles), dtype=type(mcafitresult[k]["fitarea"]) ) ret[k][j, i] = mcafitresult[k]["fitarea"] / norm[j] if "chisq" not in ret: ret["chisq"] = np.zeros((nenergies, nfiles), dtype=type(mcafit.chisq)) ret["chisq"][j, i] = mcafit.chisq # Print progress if prog is not None: prog.ndonefine(nfiles) prog.printprogress() return ret