Пример #1
0
    def testDetectorResults(self):
        from fisx import Elements
        from fisx import Detector

        elementsInstance = Elements()
        elementsInstance.initializeAsPyMca()
        
        # Make a detector from a formula
        detectorName = "NaI"
        detectorDensity = 4.0
        detectorThickness = 0.00350
        detectorInstance = Detector(detectorName,
                                    detectorDensity,
                                    detectorThickness)

        # Check the composition is returned as string and not bytes under
        # Python 3
        composition = detectorInstance.getComposition(elementsInstance)
        if sys.version_info >= (3, ):
            for key in composition:
                self.assertTrue(isinstance(key, str),
                                "Expected string, received %s" % type(key))

        # check the returned keys are correct
        self.assertTrue(len(list(composition.keys())) == 2,
                        "Incorrect number of keys returned")
        for key in ["Na", "I"]:
            self.assertTrue(key in composition,
                            "key %s not found" % key)

        thickness = detectorInstance.getThickness()
        self.assertTrue(abs( thickness - detectorThickness) < 1.0e-7,
                       "Wrong detector thickness!")

        density = detectorInstance.getDensity()
        self.assertTrue(abs(density - detectorDensity) < 1.0e-7,
                       "Wrong detector density!")

        # check the return of the getEscape method
        escape = detectorInstance.getEscape(100.0, elementsInstance)
        if sys.version_info >= (3, ):
            for key in escape:
                self.assertTrue(isinstance(key, str),
                                "Expected string, received %s" % type(key))
Пример #2
0
def _getFisxDetector(fitConfiguration, attenuatorsDetector=None):
    distance = fitConfiguration["concentrations"]["distance"]
    area = fitConfiguration["concentrations"]["area"]
    detectorMaterial = fitConfiguration["detector"]["detele"]

    if attenuatorsDetector is None:
        # user is not interested on accounting for detection efficiency
        if fitConfiguration["fit"]["escapeflag"]:
            # but wants to account for escape peaks
            # we can forget about efficiency but not about detector composition
            # assign "infinite" efficiency
            density = 0.0
            thickness = 0.0
            fisxDetector = Detector(detectorMaterial,
                                    density=density,
                                    thickness=thickness)
        else:
            # user is not interested on considering the escape peaks
            fisxDetector = None
    else:
        # make sure information is consistent
        if attenuatorsDetector[0] not in [detectorMaterial, detectorMaterial+"1"]:
            _logger.warning("%s not equal to %s",
                            attenuatorsDetector[0], detectorMaterial)
            msg = "Inconsistent detector material between DETECTOR and ATTENUATORS tab"
            msg += "\n%s not equal to %s" % (attenuatorsDetector[0], detectorMaterial)
            raise ValueError(msg)
        if len(attenuatorsDetector) == 3:
            fisxDetector = Detector(detectorMaterial,
                                density=attenuatorsDetector[1],
                                thickness=attenuatorsDetector[2])
        else:
            fisxDetector = Detector(detectorMaterial,
                                density=attenuatorsDetector[1],
                                thickness=attenuatorsDetector[2],
                                funny=attenuatorsDetector[3])
        fisxDetector.setActiveArea(area)
        fisxDetector.setDistance(distance)
    if fisxDetector is not None:
        nThreshold = fitConfiguration["detector"]["nthreshold"]
        fisxDetector.setMaximumNumberOfEscapePeaks(nThreshold)
    return fisxDetector
Пример #3
0
def _getFisxDetector(fitConfiguration, attenuatorsDetector=None):
    distance = fitConfiguration["concentrations"]["distance"]
    area = fitConfiguration["concentrations"]["area"]
    detectorMaterial = fitConfiguration["detector"]["detele"]

    if attenuatorsDetector is None:
        # user is not interested on accounting for detection efficiency
        if fitConfiguration["fit"]["escapeflag"]:
            # but wants to account for escape peaks
            # we can forget about efficiency but not about detector composition
            # assign "infinite" efficiency
            density = 0.0
            thickness = 0.0
            fisxDetector = Detector(detectorMaterial,
                                    density=density,
                                    thickness=thickness)
        else:
            # user is not interested on considering the escape peaks
            fisxDetector = None
    else:
        # make sure information is consistent
        if attenuatorsDetector[0] not in [
                detectorMaterial, detectorMaterial + "1"
        ]:
            print("%s not equal to %s" %
                  (attenuatorsDetector[0], detectorMaterial))
            msg = "Inconsistent detector material between DETECTOR and ATTENUATORS tab"
            msg += "\n%s not equal to %s" % (attenuatorsDetector[0],
                                             detectorMaterial)
            raise ValueError(msg)
        if len(attenuatorsDetector) == 3:
            fisxDetector = Detector(detectorMaterial,
                                    density=attenuatorsDetector[1],
                                    thickness=attenuatorsDetector[2])
        else:
            fisxDetector = Detector(detectorMaterial,
                                    density=attenuatorsDetector[1],
                                    thickness=attenuatorsDetector[2],
                                    funny=attenuatorsDetector[3])
        fisxDetector.setActiveArea(area)
        fisxDetector.setDistance(distance)
    if fisxDetector is not None:
        nThreshold = fitConfiguration["detector"]["nthreshold"]
        fisxDetector.setMaximumNumberOfEscapePeaks(nThreshold)
    return fisxDetector
Пример #4
0
def getMultilayerFluorescence(multilayerSample,
                              energyList,
                              layerList=None,
                              weightList=None,
                              flagList=None,
                              fulloutput=None,
                              beamFilters=None,
                              elementsList=None,
                              attenuatorList=None,
                              alphaIn=None,
                              alphaOut=None,
                              cascade=None,
                              detector=None,
                              elementsFromMatrix=False,
                              secondary=None,
                              materials=None,
                              secondaryCalculationLimit=0.0):
    if DEBUG:
        print("Library actually using secondary = ", secondary)
    global xcom
    if xcom is None:
        if DEBUG:
            print("Getting fisx elements instance")
        xcom = getElementsInstance()

    if materials is not None:
        if DEBUG:
            print("Deleting materials")
        xcom.removeMaterials()
        for material in materials:
            if DEBUG:
                print("Adding material making sure no duplicates")
            xcom.addMaterial(material, errorOnReplace=1)

    # the instance
    if DEBUG:
        print("creating XRF instance")
    xrf = XRF()

    # the beam energies
    if not len(energyList):
        raise ValueError("Empty list of beam energies!!!")
    if DEBUG:
        print("setting beam")
    xrf.setBeam(energyList, weights=weightList, characteristic=flagList)
    # the beam filters (if any)
    if beamFilters is None:
        beamFilters = []
    """
    Due to wrapping constraints, the filter list must have the form:
    [[Material name or formula0, density0, thickness0, funny factor0],
     [Material name or formula1, density1, thickness1, funny factor1],
     ...
     [Material name or formulan, densityn, thicknessn, funny factorn]]

    Unless you know what you are doing, the funny factors must be 1.0
    """
    if DEBUG:
        print("setting beamFilters")
    xrf.setBeamFilters(beamFilters)

    # the sample description
    """
    Due to wrapping constraints, the list must have the form:
    [[Material name or formula0, density0, thickness0, funny factor0],
     [Material name or formula1, density1, thickness1, funny factor1],
     ...
     [Material name or formulan, densityn, thicknessn, funny factorn]]

    Unless you know what you are doing, the funny factors must be 1.0
    """
    if DEBUG:
        print("setting sample")
    xrf.setSample(multilayerSample)

    # the attenuators
    if attenuatorList is not None:
        if len(attenuatorList) > 0:
            if DEBUG:
                print("setting attenuators")
            xrf.setAttenuators(attenuatorList)

    # the geometry
    if DEBUG:
        print("setting Geometry")
    if alphaIn is None:
        alphaIn = 45
    if alphaOut is None:
        alphaOut = 45
    xrf.setGeometry(alphaIn, alphaOut)

    # the detector
    if DEBUG:
        print("setting Detector")
    if detector is not None:
        # Detector can be a list as [material, density, thickness]
        # or a Detector instance
        if isinstance(detector, Detector):
            detectorInstance = detector
        elif len(detector) == 3:
            detectorInstance = Detector(detector[0],
                                        density=detector[1],
                                        thickness=detector[2])
        else:
            detectorInstance = Detector(detector[0],
                                        density=detector[1],
                                        thickness=detector[2],
                                        funny=detector[3])
    else:
        detectorInstance = Detector("")

    xrf.setDetector(detectorInstance)
    if detectorInstance.getActiveArea() > 0.0:
        useGeometricEfficiency = 1
    else:
        useGeometricEfficiency = 0

    matrixElementsList = []
    for peak in elementsList:
        ele = peak.split()[0]
        considerIt = False
        for layer in multilayerSample:
            composition = xcom.getComposition(layer[0])
            if ele in composition:
                considerIt = True
        if considerIt:
            if peak not in matrixElementsList:
                matrixElementsList.append(peak)

    if elementsFromMatrix:
        elementsList = matrixElementsList

    # the detector distance and solid angle ???
    if elementsList in [None, []]:
        raise ValueError("Element list not specified")

    if len(elementsList):
        if len(elementsList[0]) == 3:
            # PyMca can send [atomic number, element, peak]
            actualElementList = [x[1] + " " + x[2] for x in elementsList]
        elif len(elementsList[0]) == 2:
            actualElementList = [x[0] + " " + x[1] for x in elementsList]
        else:
            actualElementList = elementsList

    # enabling the cache gets a (miserable) 15 % speed up
    if DEBUG:
        print("Using cascade cache")
    for layer in multilayerSample:
        composition = xcom.getComposition(layer[0])
        for element in composition.keys():
            xcom.setElementCascadeCacheEnabled(element, 1)
    for element in actualElementList:
        xcom.setElementCascadeCacheEnabled(element.split()[0], 1)

    if DEBUG:
        print("Calling getMultilayerFluorescence")
        t0 = time.time()
    expectedFluorescence = xrf.getMultilayerFluorescence(
        actualElementList,
        xcom,
        secondary=secondary,
        useGeometricEfficiency=useGeometricEfficiency,
        useMassFractions=elementsFromMatrix,
        secondaryCalculationLimit=secondaryCalculationLimit)
    if DEBUG:
        print("C++ elapsed TWO = ", time.time() - t0)

    if not elementsFromMatrix:
        # If one element was present in one layer and not on others, PyMca only
        # calculated contributions from the layers in which the element was
        # present
        for peakFamily in matrixElementsList:
            element, family = peakFamily.split()[0:2]
            key = element + " " + family
            if key in expectedFluorescence:
                # those layers where the amount of the material was 0 have
                # to present no contribution
                for iLayer in range(len(expectedFluorescence[key])):
                    layerMaterial = multilayerSample[iLayer][0]
                    if element not in xcom.getComposition(layerMaterial):
                        expectedFluorescence[key][iLayer] = {}
    return expectedFluorescence
Пример #5
0
def getMultilayerFluorescence(multilayerSample,
                              energyList,
                              layerList = None,
                              weightList=None,
                              flagList  = None,
                              fulloutput = None,
                              beamFilters = None,
                              elementsList = None,
                              attenuatorList  = None,
                              alphaIn      = None,
                              alphaOut     = None,
                              cascade = None,
                              detector= None,
                              elementsFromMatrix=False,
                              secondary=None,
                              materials=None,
                              secondaryCalculationLimit=0.0):
    if DEBUG:
        print("Library actually using secondary = ", secondary)
    global xcom
    if xcom is None:
        if DEBUG:
            print("Getting fisx elements instance")
        xcom = getElementsInstance()

    if materials is not None:
        if DEBUG:
            print("Deleting materials")
        xcom.removeMaterials()
        for material in materials:
            if DEBUG:
                print("Adding material making sure no duplicates")
            xcom.addMaterial(material, errorOnReplace=1)

    # the instance
    if DEBUG:
        print("creating XRF instance")
    xrf = XRF()

    # the beam energies
    if not len(energyList):
        raise ValueError("Empty list of beam energies!!!")
    if DEBUG:
        print("setting beam")
    xrf.setBeam(energyList, weights=weightList,
                            characteristic=flagList)
    # the beam filters (if any)
    if beamFilters is None:
        beamFilters = []
    """
    Due to wrapping constraints, the filter list must have the form:
    [[Material name or formula0, density0, thickness0, funny factor0],
     [Material name or formula1, density1, thickness1, funny factor1],
     ...
     [Material name or formulan, densityn, thicknessn, funny factorn]]

    Unless you know what you are doing, the funny factors must be 1.0
    """
    if DEBUG:
        print("setting beamFilters")
    xrf.setBeamFilters(beamFilters)

    # the sample description
    """
    Due to wrapping constraints, the list must have the form:
    [[Material name or formula0, density0, thickness0, funny factor0],
     [Material name or formula1, density1, thickness1, funny factor1],
     ...
     [Material name or formulan, densityn, thicknessn, funny factorn]]

    Unless you know what you are doing, the funny factors must be 1.0
    """
    if DEBUG:
        print("setting sample")
    xrf.setSample(multilayerSample)

    # the attenuators
    if attenuatorList is not None:
        if len(attenuatorList) > 0:
            if DEBUG:
                print("setting attenuators")
            xrf.setAttenuators(attenuatorList)

    # the geometry
    if DEBUG:
        print("setting Geometry")
    if alphaIn is None:
        alphaIn = 45
    if alphaOut is None:
        alphaOut = 45
    xrf.setGeometry(alphaIn, alphaOut)

    # the detector
    if DEBUG:
        print("setting Detector")
    if detector is not None:
        # Detector can be a list as [material, density, thickness]
        # or a Detector instance
        if isinstance(detector, Detector):
            detectorInstance = detector
        elif len(detector) == 3:
            detectorInstance = Detector(detector[0],
                                            density=detector[1],
                                            thickness=detector[2])
        else:
            detectorInstance = Detector(detector[0],
                                            density=detector[1],
                                            thickness=detector[2],
                                            funny=detector[3])
    else:
        detectorInstance = Detector("")

    xrf.setDetector(detectorInstance)
    if detectorInstance.getActiveArea() > 0.0:
        useGeometricEfficiency = 1
    else:
        useGeometricEfficiency = 0

    matrixElementsList = []
    for peak in elementsList:
        ele = peak.split()[0]
        considerIt = False
        for layer in multilayerSample:
            composition = xcom.getComposition(layer[0])
            if ele in composition:
                considerIt = True
        if considerIt:
            if peak not in matrixElementsList:
                matrixElementsList.append(peak)

    if elementsFromMatrix:
        elementsList = matrixElementsList

    # the detector distance and solid angle ???
    if elementsList in [None, []]:
        raise ValueError("Element list not specified")

    if len(elementsList):
        if len(elementsList[0]) == 3:
            # PyMca can send [atomic number, element, peak]
            actualElementList = [x[1] + " " + x[2] for x in elementsList]
        elif len(elementsList[0]) == 2:
            actualElementList = [x[0] + " " + x[1] for x in elementsList]
        else:
            actualElementList = elementsList

    # enabling the cache gets a (miserable) 15 % speed up
    if DEBUG:
        print("Using cascade cache")
    for layer in multilayerSample:
        composition = xcom.getComposition(layer[0])
        for element in composition.keys():
            xcom.setElementCascadeCacheEnabled(element, 1)
    for element in actualElementList:
        xcom.setElementCascadeCacheEnabled(element.split()[0], 1)

    if DEBUG:
        print("Calling getMultilayerFluorescence")
        t0 = time.time()
    expectedFluorescence = xrf.getMultilayerFluorescence(actualElementList,
                            xcom,
                            secondary=secondary,
                            useGeometricEfficiency=useGeometricEfficiency,
                            useMassFractions=elementsFromMatrix,
                            secondaryCalculationLimit=secondaryCalculationLimit)
    if DEBUG:
        print("C++ elapsed TWO = ", time.time() - t0)

    if not elementsFromMatrix:
        # If one element was present in one layer and not on others, PyMca only
        # calculated contributions from the layers in which the element was
        # present
        for peakFamily in matrixElementsList:
            element, family = peakFamily.split()[0:2]
            key = element + " " + family
            if key in expectedFluorescence:
                # those layers where the amount of the material was 0 have
                # to present no contribution
                for iLayer in range(len(expectedFluorescence[key])):
                    layerMaterial = multilayerSample[iLayer][0]
                    if element not in xcom.getComposition(layerMaterial):
                        expectedFluorescence[key][iLayer] = {}
    return expectedFluorescence
Пример #6
0
    def testXRFResults(self):
        from fisx import Elements
        from fisx import Material
        from fisx import Detector
        from fisx import XRF

        elementsInstance = Elements()
        elementsInstance.initializeAsPyMca()
        # After the slow initialization (to be made once), the rest is fairly fast.
        xrf = XRF()
        xrf.setBeam(
            16.0)  # set incident beam as a single photon energy of 16 keV
        xrf.setBeamFilters([["Al1", 2.72, 0.11, 1.0]])  # Incident beam filters
        # Steel composition of Schoonjans et al, 2012 used to generate table I
        steel = {
            "C": 0.0445,
            "N": 0.04,
            "Si": 0.5093,
            "P": 0.02,
            "S": 0.0175,
            "V": 0.05,
            "Cr": 18.37,
            "Mn": 1.619,
            "Fe":
            64.314,  # calculated by subtracting the sum of all other elements
            "Co": 0.109,
            "Ni": 12.35,
            "Cu": 0.175,
            "As": 0.010670,
            "Mo": 2.26,
            "W": 0.11,
            "Pb": 0.001
        }
        SRM_1155 = Material("SRM_1155", 1.0, 1.0)
        SRM_1155.setComposition(steel)
        elementsInstance.addMaterial(SRM_1155)
        xrf.setSample([["SRM_1155", 1.0,
                        1.0]])  # Sample, density and thickness
        xrf.setGeometry(45., 45.)  # Incident and fluorescent beam angles
        detector = Detector("Si1", 2.33,
                            0.035)  # Detector Material, density, thickness
        detector.setActiveArea(0.50)  # Area and distance in consistent units
        detector.setDistance(2.1)  # expected cm2 and cm.
        xrf.setDetector(detector)
        Air = Material("Air", 0.0012048, 1.0)
        Air.setCompositionFromLists(
            ["C1", "N1", "O1", "Ar1", "Kr1"],
            [0.0012048, 0.75527, 0.23178, 0.012827, 3.2e-06])
        elementsInstance.addMaterial(Air)
        xrf.setAttenuators([["Air", 0.0012048, 5.0, 1.0],
                            ["Be1", 1.848, 0.002, 1.0]])  # Attenuators
        fluo = xrf.getMultilayerFluorescence(["Cr K", "Fe K", "Ni K"],
                                             elementsInstance,
                                             secondary=2,
                                             useMassFractions=1)
        print(
            "\nElement   Peak          Energy       Rate      Secondary  Tertiary"
        )
        for key in fluo:
            for layer in fluo[key]:
                peakList = list(fluo[key][layer].keys())
                peakList.sort()
                for peak in peakList:
                    # energy of the peak
                    energy = fluo[key][layer][peak]["energy"]
                    # expected measured rate
                    rate = fluo[key][layer][peak]["rate"]
                    # primary photons (no attenuation and no detector considered)
                    primary = fluo[key][layer][peak]["primary"]
                    # secondary photons (no attenuation and no detector considered)
                    secondary = fluo[key][layer][peak]["secondary"]
                    # tertiary photons (no attenuation and no detector considered)
                    tertiary = fluo[key][layer][peak].get("tertiary", 0.0)
                    # correction due to secondary excitation
                    enhancement2 = (primary + secondary) / primary
                    enhancement3 = (primary + secondary + tertiary) / primary
                    print("%s   %s    %.4f     %.3g     %.5g    %.5g" % \
                                       (key, peak + (13 - len(peak)) * " ", energy,
                                       rate, enhancement2, enhancement3))
                    # compare against expected values from Schoonjans et al.
                    testXMI = True
                    if (key == "Cr K") and peak.startswith("KL3"):
                        second = 1.626
                        third = 1.671
                    elif (key == "Cr K") and peak.startswith("KM3"):
                        second = 1.646
                        third = 1.694
                    elif (key == "Fe K") and peak.startswith("KL3"):
                        second = 1.063
                        third = 1.064
                    elif (key == "Fe K") and peak.startswith("KL3"):
                        second = 1.065
                        third = 1.066
                    else:
                        testXMI = False
                    if testXMI:
                        discrepancy = 100 * (abs(second - enhancement2) /
                                             second)
                        self.assertTrue(discrepancy < 1.5,
                            "%s %s secondary discrepancy = %.1f %%" % \
                            (key, peak, discrepancy))
                        discrepancy = 100 * (abs(third - enhancement3) / third)
                        self.assertTrue(discrepancy < 1.5,
                            "%s %s tertiary discrepancy = %.1f %%" % \
                            (key, peak, discrepancy))
Пример #7
0
def getMultilayerFluorescence(multilayerSample,
                              energyList,
                              layerList=None,
                              weightList=None,
                              flagList=None,
                              fulloutput=None,
                              beamFilters=None,
                              elementsList=None,
                              attenuatorList=None,
                              userattenuatorList=None,
                              alphaIn=None,
                              alphaOut=None,
                              cascade=None,
                              detector=None,
                              elementsFromMatrix=False,
                              secondary=None,
                              materials=None,
                              secondaryCalculationLimit=None,
                              cache=1):

    if secondary is None:
        secondary = 0
    if secondaryCalculationLimit is None:
        secondaryCalculationLimit = 0.0
    if cache:
        cache = 1
    else:
        cache = 0

    _logger.info("Library requested to use secondary = %s", secondary)
    _logger.info("Library requested to use secondary limit = %s",
                 secondaryCalculationLimit)
    _logger.info("Library requested to use cache = %d", cache)

    global xcom
    if xcom is None:
        _logger.debug("Getting fisx elements instance")
        xcom = getElementsInstance()

    if materials is not None:
        _logger.debug("Deleting materials")
        xcom.removeMaterials()
        for material in materials:
            _logger.debug("Adding material making sure no duplicates")
            xcom.addMaterial(material, errorOnReplace=1)

    # the instance
    _logger.debug("creating XRF instance")
    xrf = XRF()

    # the beam energies
    if not len(energyList):
        raise ValueError("Empty list of beam energies!!!")
    _logger.debug("setting beam")
    xrf.setBeam(energyList, weights=weightList, characteristic=flagList)
    # the beam filters (if any)
    if beamFilters is None:
        beamFilters = []
    """
    Due to wrapping constraints, the filter list must have the form:
    [[Material name or formula0, density0, thickness0, funny factor0],
     [Material name or formula1, density1, thickness1, funny factor1],
     ...
     [Material name or formulan, densityn, thicknessn, funny factorn]]

    Unless you know what you are doing, the funny factors must be 1.0
    """
    _logger.debug("setting beamFilters")
    xrf.setBeamFilters(beamFilters)

    # the sample description
    """
    Due to wrapping constraints, the list must have the form:
    [[Material name or formula0, density0, thickness0, funny factor0],
     [Material name or formula1, density1, thickness1, funny factor1],
     ...
     [Material name or formulan, densityn, thicknessn, funny factorn]]

    Unless you know what you are doing, the funny factors must be 1.0
    """
    _logger.debug("setting sample")
    xrf.setSample(multilayerSample)

    # the attenuators
    if attenuatorList is not None:
        if len(attenuatorList) > 0:
            _logger.debug("setting attenuators")
            xrf.setAttenuators(attenuatorList)

    # the user attenuators
    if userattenuatorList is not None:
        i = 0
        for userAttenuator in userattenuatorList:
            if isinstance(userAttenuator, tuple) or \
               isinstance(userAttenuator, list):
                energy = userAttenuator[0]
                transmission = userAttenuator[1]
                if len(userAttenuator) == 4:
                    name = userAttenuator[2]
                    comment = userAttenuator[3]
            else:
                if userattenuatorList[userAttenuator]["use"]:
                    energy = userattenuatorList[userAttenuator]["energy"]
                    transmission = userattenuatorList[userAttenuator][
                        "transmission"]
                    name = userattenuatorList[userAttenuator].get(
                        "name", "UserFilter%d" % i)
                    name = userattenuatorList[userAttenuator].get(
                        "comment", "")
                else:
                    continue
            ttable = TransmissionTable()
            ttable.setTransmissionTableFromLists(energy, transmission, name,
                                                 comment)
            xrf.setTransmissionTable(ttable)

    # the geometry
    _logger.debug("setting Geometry")
    if alphaIn is None:
        alphaIn = 45
    if alphaOut is None:
        alphaOut = 45
    xrf.setGeometry(alphaIn, alphaOut)

    # the detector
    _logger.debug("setting Detector")
    if detector is not None:
        # Detector can be a list as [material, density, thickness]
        # or a Detector instance
        if isinstance(detector, Detector):
            detectorInstance = detector
        elif len(detector) == 3:
            detectorInstance = Detector(detector[0],
                                        density=detector[1],
                                        thickness=detector[2])
        else:
            detectorInstance = Detector(detector[0],
                                        density=detector[1],
                                        thickness=detector[2],
                                        funny=detector[3])
    else:
        detectorInstance = Detector("")

    xrf.setDetector(detectorInstance)
    if detectorInstance.getActiveArea() > 0.0:
        useGeometricEfficiency = 1
    else:
        useGeometricEfficiency = 0

    if elementsList in [None, []]:
        raise ValueError("Element list not specified")

    if len(elementsList):
        if len(elementsList[0]) == 3:
            # PyMca can send [atomic number, element, peak]
            actualElementsList = [x[1] + " " + x[2] for x in elementsList]
        elif len(elementsList[0]) == 2:
            actualElementsList = [x[0] + " " + x[1] for x in elementsList]
        else:
            actualElementsList = elementsList

    matrixElementsList = []
    for peak in actualElementsList:
        ele = peak.split()[0]
        considerIt = False
        for layer in multilayerSample:
            composition = xcom.getComposition(layer[0])
            if ele in composition:
                considerIt = True
        if considerIt:
            if peak not in matrixElementsList:
                matrixElementsList.append(peak)

    if elementsFromMatrix:
        elementsList = matrixElementsList

    t0 = time.time()
    if cache:
        # enabling the cascade cache gets a (miserable) 15 % speed up
        _logger.debug("FisxHelper Using cache")
    else:
        _logger.debug("FisxHelper Not using cache")

    treatedElements = []
    emittedLines = []
    for actualElement in actualElementsList:
        element = actualElement.split()[0]
        if element not in treatedElements:
            if cache:
                lines = xcom.getEmittedXRayLines(element)
                sampleEnergies = [lines[key] for key in lines]
                for e in sampleEnergies:
                    if e not in emittedLines:
                        emittedLines.append(e)
            treatedElements.append(element)

    for layer in multilayerSample:
        composition = xcom.getComposition(layer[0])
        for element in composition.keys():
            if element not in treatedElements:
                if cache:
                    lines = xcom.getEmittedXRayLines(element)
                    sampleEnergies = [lines[key] for key in lines]
                    for e in sampleEnergies:
                        if e not in emittedLines:
                            emittedLines.append(e)
                treatedElements.append(element)

    if attenuatorList is not None:
        for layer in attenuatorList:
            composition = xcom.getComposition(layer[0])
            for element in composition.keys():
                if element not in treatedElements:
                    if cache:
                        lines = xcom.getEmittedXRayLines(element)
                        sampleEnergies = [lines[key] for key in lines]
                        for e in sampleEnergies:
                            if e not in emittedLines:
                                emittedLines.append(e)
                    treatedElements.append(element)

    if hasattr(xcom, "updateCache"):
        composition = detectorInstance.getComposition(xcom)
        for element in composition.keys():
            if element not in treatedElements:
                if cache:
                    lines = xcom.getEmittedXRayLines(element)
                    sampleEnergies = [lines[key] for key in lines]
                    for e in sampleEnergies:
                        if e not in emittedLines:
                            emittedLines.append(e)
                treatedElements.append(element)

        for element in actualElementsList:
            if element.split()[0] not in treatedElements:
                treatedElements.append(element.split()[0])

        for element in treatedElements:
            # this limit seems overestimated but still reasonable
            if xcom.getCacheSize(element) > 5000:
                _logger.info("Clearing cache for %s" % element)
                xcom.clearCache(element)
            if cache:
                _logger.info("Updating cache for %s" % element)
                xcom.updateCache(element, energyList)
                xcom.updateCache(element, emittedLines)
            else:
                # should I clear the cache to be sure?
                # for the time being, yes.
                _logger.info("No cache. Clearing cache for %s" % element)
                xcom.clearCache(element)
            xcom.setCacheEnabled(element, cache)
            _logger.info("Element %s cache size = %d", element,
                         xcom.getCacheSize(element))
        for element in actualElementsList:
            xcom.setElementCascadeCacheEnabled(element.split()[0], cache)

    if hasattr(xcom, "updateEscapeCache") and \
       hasattr(xcom, "setEscapeCacheEnabled"):
        if detector is not None:
            for element in actualElementsList:
                if cache:
                    lines = xcom.getEmittedXRayLines(element.split()[0])
                    lines_energy = [lines[key] for key in lines]
                    for e in lines_energy:
                        if e not in emittedLines:
                            emittedLines.append(e)
            if not cache:
                if hasattr(xcom, "clearEscapeCache"):
                    # the method is there but nor wrapped yet
                    xcom.clearEscapeCache()
            xcom.setEscapeCacheEnabled(cache)
            if cache:
                xcom.updateEscapeCache(detectorInstance.getComposition(xcom),
                            emittedLines,
                            energyThreshold=detectorInstance.getEscapePeakEnergyThreshold(), \
                            intensityThreshold=detectorInstance.getEscapePeakIntensityThreshold(), \
                            nThreshold=detectorInstance.getEscapePeakNThreshold(), \
                            alphaIn=detectorInstance.getEscapePeakAlphaIn(),
                            thickness=0)  # No escape by the back considered yet
    else:
        _logger.debug("NOT CALLING UPDATE CACHE")
    _logger.info("C++ elapsed filling cache = %s", time.time() - t0)

    _logger.debug("Calling getMultilayerFluorescence")
    t0 = time.time()
    expectedFluorescence = xrf.getMultilayerFluorescence(
        actualElementsList,
        xcom,
        secondary=secondary,
        useGeometricEfficiency=useGeometricEfficiency,
        useMassFractions=elementsFromMatrix,
        secondaryCalculationLimit=secondaryCalculationLimit)
    _logger.info("C++ elapsed TWO = %s", time.time() - t0)
    if not elementsFromMatrix:
        # If one element was present in one layer and not on others, PyMca only
        # calculated contributions from the layers in which the element was
        # present
        for peakFamily in matrixElementsList:
            element, family = peakFamily.split()[0:2]
            key = element + " " + family
            if key in expectedFluorescence:
                # those layers where the amount of the material was 0 have
                # to present no contribution
                for iLayer in range(len(expectedFluorescence[key])):
                    layerMaterial = multilayerSample[iLayer][0]
                    if element not in xcom.getComposition(layerMaterial):
                        expectedFluorescence[key][iLayer] = {}
    return expectedFluorescence
Пример #8
0
    def testXRFResults(self):
        from fisx import Elements
        from fisx import Material
        from fisx import Detector
        from fisx import XRF

        elementsInstance = Elements()
        elementsInstance.initializeAsPyMca()
        # After the slow initialization (to be made once), the rest is fairly fast.
        xrf = XRF()
        xrf.setBeam(16.0) # set incident beam as a single photon energy of 16 keV
        xrf.setBeamFilters([["Al1", 2.72, 0.11, 1.0]]) # Incident beam filters
        # Steel composition of Schoonjans et al, 2012 used to generate table I
        steel = {"C":  0.0445,
                 "N":  0.04,
                 "Si": 0.5093,
                 "P":  0.02,
                 "S":  0.0175,
                 "V":  0.05,
                 "Cr":18.37,
                 "Mn": 1.619,
                 "Fe":64.314, # calculated by subtracting the sum of all other elements
                 "Co": 0.109,
                 "Ni":12.35,
                 "Cu": 0.175,
                 "As": 0.010670,
                 "Mo": 2.26,
                 "W":  0.11,
                 "Pb": 0.001}
        SRM_1155 = Material("SRM_1155", 1.0, 1.0)
        SRM_1155.setComposition(steel)
        elementsInstance.addMaterial(SRM_1155)
        xrf.setSample([["SRM_1155", 1.0, 1.0]]) # Sample, density and thickness
        xrf.setGeometry(45., 45.)               # Incident and fluorescent beam angles
        detector = Detector("Si1", 2.33, 0.035) # Detector Material, density, thickness
        detector.setActiveArea(0.50)            # Area and distance in consistent units
        detector.setDistance(2.1)               # expected cm2 and cm.
        xrf.setDetector(detector)
        Air = Material("Air", 0.0012048, 1.0)
        Air.setCompositionFromLists(["C1", "N1", "O1", "Ar1", "Kr1"],
                                    [0.0012048, 0.75527, 0.23178, 0.012827, 3.2e-06])
        elementsInstance.addMaterial(Air)
        xrf.setAttenuators([["Air", 0.0012048, 5.0, 1.0],
                            ["Be1", 1.848, 0.002, 1.0]]) # Attenuators
        fluo = xrf.getMultilayerFluorescence(["Cr K", "Fe K", "Ni K"],
                                             elementsInstance,
                                             secondary=2,
                                             useMassFractions=1)
        print("\nElement   Peak          Energy       Rate      Secondary  Tertiary")
        for key in fluo:
            for layer in fluo[key]:
                peakList = list(fluo[key][layer].keys())
                peakList.sort()
                for peak in peakList:
                    # energy of the peak
                    energy = fluo[key][layer][peak]["energy"]
                    # expected measured rate
                    rate = fluo[key][layer][peak]["rate"]
                    # primary photons (no attenuation and no detector considered)
                    primary = fluo[key][layer][peak]["primary"]
                    # secondary photons (no attenuation and no detector considered)
                    secondary = fluo[key][layer][peak]["secondary"]
                    # tertiary photons (no attenuation and no detector considered)
                    tertiary = fluo[key][layer][peak].get("tertiary", 0.0)
                    # correction due to secondary excitation
                    enhancement2 = (primary + secondary) / primary
                    enhancement3 = (primary + secondary + tertiary) / primary
                    print("%s   %s    %.4f     %.3g     %.5g    %.5g" % \
                                       (key, peak + (13 - len(peak)) * " ", energy,
                                       rate, enhancement2, enhancement3))
                    # compare against expected values from Schoonjans et al.
                    testXMI = True
                    if (key == "Cr K") and peak.startswith("KL3"):
                        second = 1.626
                        third = 1.671
                    elif (key == "Cr K") and peak.startswith("KM3"):
                        second = 1.646
                        third = 1.694
                    elif (key == "Fe K") and peak.startswith("KL3"):
                        second = 1.063
                        third = 1.064
                    elif (key == "Fe K") and peak.startswith("KL3"):
                        second = 1.065
                        third = 1.066
                    else:
                        testXMI = False
                    if testXMI:
                        discrepancy = 100 * (abs(second-enhancement2)/second)
                        self.assertTrue(discrepancy < 1.5,
                            "%s %s secondary discrepancy = %.1f %%" % \
                            (key, peak, discrepancy))
                        discrepancy = 100 * (abs(third-enhancement3)/third)
                        self.assertTrue(discrepancy < 1.5,
                            "%s %s tertiary discrepancy = %.1f %%" % \
                            (key, peak, discrepancy))
Пример #9
0
def getMultilayerFluorescence(multilayerSample,
                              energyList,
                              layerList = None,
                              weightList=None,
                              flagList  = None,
                              fulloutput = None,
                              beamFilters = None,
                              elementsList = None,
                              attenuatorList  = None,
                              alphaIn      = None,
                              alphaOut     = None,
                              cascade = None,
                              detector= None,
                              elementsFromMatrix=False,
                              secondary=None,
                              materials=None,
                              secondaryCalculationLimit=None,
                              cache=1):

    if secondary is None:
        secondary=0
    if secondaryCalculationLimit is None:
        secondaryCalculationLimit=0.0
    if cache:
        cache = 1
    else:
        cache = 0

    _logger.info("Library requested to use secondary = %s", secondary)
    _logger.info("Library requested to use secondary limit = %s", secondaryCalculationLimit)
    _logger.info("Library requested to use cache = %d", cache)

    global xcom
    if xcom is None:
        _logger.debug("Getting fisx elements instance")
        xcom = getElementsInstance()

    if materials is not None:
        _logger.debug("Deleting materials")
        xcom.removeMaterials()
        for material in materials:
            _logger.debug("Adding material making sure no duplicates")
            xcom.addMaterial(material, errorOnReplace=1)

    # the instance
    _logger.debug("creating XRF instance")
    xrf = XRF()

    # the beam energies
    if not len(energyList):
        raise ValueError("Empty list of beam energies!!!")
    _logger.debug("setting beam")
    xrf.setBeam(energyList, weights=weightList,
                            characteristic=flagList)
    # the beam filters (if any)
    if beamFilters is None:
        beamFilters = []
    """
    Due to wrapping constraints, the filter list must have the form:
    [[Material name or formula0, density0, thickness0, funny factor0],
     [Material name or formula1, density1, thickness1, funny factor1],
     ...
     [Material name or formulan, densityn, thicknessn, funny factorn]]

    Unless you know what you are doing, the funny factors must be 1.0
    """
    _logger.debug("setting beamFilters")
    xrf.setBeamFilters(beamFilters)

    # the sample description
    """
    Due to wrapping constraints, the list must have the form:
    [[Material name or formula0, density0, thickness0, funny factor0],
     [Material name or formula1, density1, thickness1, funny factor1],
     ...
     [Material name or formulan, densityn, thicknessn, funny factorn]]

    Unless you know what you are doing, the funny factors must be 1.0
    """
    _logger.debug("setting sample")
    xrf.setSample(multilayerSample)

    # the attenuators
    if attenuatorList is not None:
        if len(attenuatorList) > 0:
            _logger.debug("setting attenuators")
            xrf.setAttenuators(attenuatorList)

    # the geometry
    _logger.debug("setting Geometry")
    if alphaIn is None:
        alphaIn = 45
    if alphaOut is None:
        alphaOut = 45
    xrf.setGeometry(alphaIn, alphaOut)

    # the detector
    _logger.debug("setting Detector")
    if detector is not None:
        # Detector can be a list as [material, density, thickness]
        # or a Detector instance
        if isinstance(detector, Detector):
            detectorInstance = detector
        elif len(detector) == 3:
            detectorInstance = Detector(detector[0],
                                            density=detector[1],
                                            thickness=detector[2])
        else:
            detectorInstance = Detector(detector[0],
                                            density=detector[1],
                                            thickness=detector[2],
                                            funny=detector[3])
    else:
        detectorInstance = Detector("")

    xrf.setDetector(detectorInstance)
    if detectorInstance.getActiveArea() > 0.0:
        useGeometricEfficiency = 1
    else:
        useGeometricEfficiency = 0

    if elementsList in [None, []]:
        raise ValueError("Element list not specified")

    if len(elementsList):
        if len(elementsList[0]) == 3:
            # PyMca can send [atomic number, element, peak]
            actualElementsList = [x[1] + " " + x[2] for x in elementsList]
        elif len(elementsList[0]) == 2:
            actualElementsList = [x[0] + " " + x[1] for x in elementsList]
        else:
            actualElementsList = elementsList

    matrixElementsList = []
    for peak in actualElementsList:
        ele = peak.split()[0]
        considerIt = False
        for layer in multilayerSample:
            composition = xcom.getComposition(layer[0])
            if ele in composition:
                considerIt = True
        if considerIt:
            if peak not in matrixElementsList:
                matrixElementsList.append(peak)

    if elementsFromMatrix:
        elementsList = matrixElementsList

    t0 = time.time()
    if cache:
        # enabling the cascade cache gets a (miserable) 15 % speed up
        _logger.debug("FisxHelper Using cache")
    else:
        _logger.debug("FisxHelper Not using cache")

    treatedElements = []
    emittedLines = []
    for actualElement in actualElementsList:
        element = actualElement.split()[0]
        if element not in treatedElements:
            if cache:
                lines = xcom.getEmittedXRayLines(element)
                sampleEnergies = [lines[key] for key in lines]
                for e in sampleEnergies:
                    if e not in emittedLines:
                        emittedLines.append(e)
            treatedElements.append(element)

    for layer in multilayerSample:
        composition = xcom.getComposition(layer[0])
        for element in composition.keys():
            if element not in treatedElements:
                if cache:
                    lines = xcom.getEmittedXRayLines(element)
                    sampleEnergies = [lines[key] for key in lines]
                    for e in sampleEnergies:
                        if e not in emittedLines:
                            emittedLines.append(e)
                treatedElements.append(element)

    if attenuatorList is not None:
        for layer in attenuatorList:
            composition = xcom.getComposition(layer[0])
            for element in composition.keys():
                if element not in treatedElements:
                    if cache:
                        lines = xcom.getEmittedXRayLines(element)
                        sampleEnergies = [lines[key] for key in lines]
                        for e in sampleEnergies:
                            if e not in emittedLines:
                                emittedLines.append(e)
                    treatedElements.append(element)

    if hasattr(xcom, "updateCache"):
        composition = detectorInstance.getComposition(xcom)
        for element in composition.keys():
            if element not in treatedElements:
                if cache:
                    lines = xcom.getEmittedXRayLines(element)
                    sampleEnergies = [lines[key] for key in lines]
                    for e in sampleEnergies:
                        if e not in emittedLines:
                            emittedLines.append(e)
                treatedElements.append(element)

        for element in actualElementsList:
            if element.split()[0] not in treatedElements:
                treatedElements.append(element.split()[0])

        for element in treatedElements:
            # this limit seems overestimated but still reasonable
            if xcom.getCacheSize(element) > 5000:
                _logger.info("Clearing cache for %s" % element)
                xcom.clearCache(element)
            if cache:
                _logger.info("Updating cache for %s" % element)
                xcom.updateCache(element, energyList)
                xcom.updateCache(element, emittedLines)
            else:
                # should I clear the cache to be sure?
                # for the time being, yes.
                _logger.info("No cache. Clearing cache for %s" % element)
                xcom.clearCache(element)
            xcom.setCacheEnabled(element, cache)
            _logger.info("Element %s cache size = %d",
                          element, xcom.getCacheSize(element))
        for element in actualElementsList:
            xcom.setElementCascadeCacheEnabled(element.split()[0], cache)

    if hasattr(xcom, "updateEscapeCache") and \
       hasattr(xcom, "setEscapeCacheEnabled"):
        if detector is not None:
            for element in actualElementsList:
                if cache:
                    lines = xcom.getEmittedXRayLines(element.split()[0])
                    lines_energy = [lines[key] for key in lines]
                    for e in lines_energy:
                        if e not in emittedLines:
                            emittedLines.append(e)
            if not cache:
                if hasattr(xcom, "clearEscapeCache"):
                    # the method is there but nor wrapped yet
                    xcom.clearEscapeCache()
            xcom.setEscapeCacheEnabled(cache)
            if cache:
                xcom.updateEscapeCache(detectorInstance.getComposition(xcom),
                            emittedLines,
                            energyThreshold=detectorInstance.getEscapePeakEnergyThreshold(), \
                            intensityThreshold=detectorInstance.getEscapePeakIntensityThreshold(), \
                            nThreshold=detectorInstance.getEscapePeakNThreshold(), \
                            alphaIn=detectorInstance.getEscapePeakAlphaIn(),
                            thickness=0)  # No escape by the back considered yet
    else:
        _logger.debug("NOT CALLING UPDATE CACHE")
    _logger.info("C++ elapsed filling cache = %s",
                  time.time() - t0)
        
    _logger.debug("Calling getMultilayerFluorescence")
    t0 = time.time()
    expectedFluorescence = xrf.getMultilayerFluorescence(actualElementsList,
                            xcom,
                            secondary=secondary,
                            useGeometricEfficiency=useGeometricEfficiency,
                            useMassFractions=elementsFromMatrix,
                            secondaryCalculationLimit=secondaryCalculationLimit)
    _logger.info("C++ elapsed TWO = %s", time.time() - t0)
    if not elementsFromMatrix:
        # If one element was present in one layer and not on others, PyMca only
        # calculated contributions from the layers in which the element was
        # present
        for peakFamily in matrixElementsList:
            element, family = peakFamily.split()[0:2]
            key = element + " " + family
            if key in expectedFluorescence:
                # those layers where the amount of the material was 0 have
                # to present no contribution
                for iLayer in range(len(expectedFluorescence[key])):
                    layerMaterial = multilayerSample[iLayer][0]
                    if element not in xcom.getComposition(layerMaterial):
                        expectedFluorescence[key][iLayer] = {}
    return expectedFluorescence