Exemple #1
0
    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
Exemple #2
0
 def __init__(self):
     self.mcafit = ClassMcaTheory.McaTheory()
     self.ctool = ConcentrationsTool.ConcentrationsTool()
     self.app = None
Exemple #3
0
    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))
Exemple #4
0
    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))
Exemple #5
0
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