def _getFisxMaterials(fitConfiguration): """ Given a PyMca fir configuration, return the list of fisx materials to be used by the library for calculation purposes. """ global xcom if xcom is None: xcom = getElementsInstance() # define all the needed materials inputMaterialDict = fitConfiguration.get("materials", {}) inputMaterialList = list(inputMaterialDict.keys()) nMaterials = len(inputMaterialList) fisxMaterials = [] processedMaterialList = [] while (len(processedMaterialList) != nMaterials): for i in range(nMaterials): materialName = inputMaterialList[i] if materialName in processedMaterialList: # already defined pass else: thickness = inputMaterialDict[materialName].get("Thickness", 1.0) density = inputMaterialDict[materialName].get("Density", 1.0) comment = inputMaterialDict[materialName].get("Comment", "") if not len(comment): comment = "" compoundList = inputMaterialDict[materialName]["CompoundList"] fractionList = inputMaterialDict[materialName]["CompoundFraction"] if not hasattr(fractionList, "__getitem__"): compoundList = [compoundList] fractionList = [fractionList] composition = {} for n in range(len(compoundList)): composition[compoundList[n]] = fractionList[n] # check the composition is expressed in terms of elements # and not in terms of other undefined materials totallyDefined = True for element in composition: #check if it can be understood if not len(xcom.getComposition(element)): # compound not understood # probably we have a material defined in terms of other material totallyDefined = False if totallyDefined: fisxMaterial = Material(materialName, density=density, thickness=thickness, comment=comment) fisxMaterial.setComposition(composition) fisxMaterials.append(fisxMaterial) processedMaterialList.append(materialName) return fisxMaterials
def _getFisxMaterials(fitConfiguration): """ Given a PyMca fir configuration, return the list of fisx materials to be used by the library for calculation purposes. """ global xcom if xcom is None: xcom = getElementsInstance() # define all the needed materials inputMaterialDict = fitConfiguration.get("materials", {}) inputMaterialList = list(inputMaterialDict.keys()) nMaterials = len(inputMaterialList) fisxMaterials = [] processedMaterialList = [] while (len(processedMaterialList) != nMaterials): for i in range(nMaterials): materialName = inputMaterialList[i] if materialName in processedMaterialList: # already defined pass else: thickness = inputMaterialDict[materialName].get( "Thickness", 1.0) density = inputMaterialDict[materialName].get("Density", 1.0) comment = inputMaterialDict[materialName].get("Comment", "") if type(comment) in [type([])]: # the user may have put a comma in the comment leading to # misinterpretation of the string as a list if len(comment) == 0: comment = "" elif len(comment) == 1: comment = comment[0] else: actualComment = comment[0] for commentPiece in comment[1:]: actualComment = actualComment + "," + commentPiece comment = actualComment if not len(comment): comment = "" compoundList = inputMaterialDict[materialName]["CompoundList"] fractionList = inputMaterialDict[materialName][ "CompoundFraction"] if not hasattr(fractionList, "__getitem__"): compoundList = [compoundList] fractionList = [fractionList] composition = {} for n in range(len(compoundList)): composition[compoundList[n]] = fractionList[n] # check the composition is expressed in terms of elements # and not in terms of other undefined materials totallyDefined = True for element in composition: #check if it can be understood if element in processedMaterialList: # already defined continue elif not len(xcom.getComposition(element)): # compound not understood # probably we have a material defined in terms of other material totallyDefined = False if totallyDefined: try: fisxMaterial = Material(materialName, density=density, thickness=thickness, comment=comment) fisxMaterial.setComposition(composition) fisxMaterials.append(fisxMaterial) except: if len(materialName): raise TypeError("Error defining material <%s>" % \ materialName) processedMaterialList.append(materialName) return fisxMaterials
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))
def _getFisxMaterials(fitConfiguration): """ Given a PyMca fir configuration, return the list of fisx materials to be used by the library for calculation purposes. """ global xcom if xcom is None: xcom = getElementsInstance() # define all the needed materials inputMaterialDict = fitConfiguration.get("materials", {}) inputMaterialList = list(inputMaterialDict.keys()) nMaterials = len(inputMaterialList) fisxMaterials = [] processedMaterialList = [] nIter = 10000 while (len(processedMaterialList) != nMaterials) and (nIter > 0): nIter -= 1 for i in range(nMaterials): materialName = inputMaterialList[i] if materialName in processedMaterialList: # already defined pass else: thickness = inputMaterialDict[materialName].get( "Thickness", 1.0) if thickness <= 0: raise ValueError("Invalid thickness %f" % thickness) density = inputMaterialDict[materialName].get("Density", 1.0) if density == 0.0: raise ValueError("Invalid density %f" % density) comment = inputMaterialDict[materialName].get("Comment", "") if type(comment) in [type([])]: # the user may have put a comma in the comment leading to # misinterpretation of the string as a list if len(comment) == 0: comment = "" elif len(comment) == 1: comment = comment[0] else: actualComment = comment[0] for commentPiece in comment[1:]: actualComment = actualComment + "," + commentPiece comment = actualComment if not len(comment): comment = "" compoundList = inputMaterialDict[materialName]["CompoundList"] fractionList = inputMaterialDict[materialName][ "CompoundFraction"] if not hasattr(fractionList, "__getitem__"): compoundList = [compoundList] fractionList = [fractionList] composition = {} for n in range(len(compoundList)): if fractionList[n] > 0.0: composition[compoundList[n]] = fractionList[n] else: _logger.info("ignoring %s, fraction = %s", compoundList[n], fractionList[n]) # check the composition is expressed in terms of elements # and not in terms of other undefined materials totallyDefined = True for element in composition: #check if it can be understood if element in processedMaterialList: # already defined continue elif not len(xcom.getComposition(element)): # compound not understood # probably we have a material defined in terms of other material totallyDefined = False if totallyDefined: try: fisxMaterial = Material(materialName, density=density, thickness=thickness, comment=comment) fisxMaterial.setComposition(composition) fisxMaterials.append(fisxMaterial) except: if len(materialName): raise TypeError("Error defining material <%s>" % \ materialName) processedMaterialList.append(materialName) if len(processedMaterialList) < nMaterials: txt = "Undefined materials. " for material in inputMaterialList: if material not in processedMaterialList: txt += "\nCannot define material <%s>\nComposition " % material compoundList = inputMaterialDict[material]["CompoundList"] fractionList = inputMaterialDict[material]["CompoundFraction"] for compound in compoundList: if not len(xcom.getComposition(compound)): if compound not in processedMaterialList: if compound + " " in processedMaterialList: txt += "contains <%s> (defined as <%s>), " % ( compound, compound + " ") else: txt += "contains <%s> (undefined)," % compound _logger.info(txt) raise KeyError(txt) return fisxMaterials
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))
def _getFisxMaterials(webConfiguration, elementsInstance=None): """ Given a user configuration, return the list of fisx materials to be used by the library for calculation purposes. """ if elementsInstance is None: elementsInstance = getElementsInstance() # define all the needed materials # Web to module translator to simplify updates Thickness = "thickness" Density = "density" CompoundList = "compounds" CompoundFraction = "mass" Comment = "comment" Name = "name" inputMaterialList = webConfiguration.get("materials", []) nMaterials = len(inputMaterialList) fisxMaterials = [] processedMaterialList = [] lastProcessedMaterial = None while (len(processedMaterialList) != nMaterials): for i in range(nMaterials): inputMaterialDict = inputMaterialList[i] materialName = inputMaterialDict[Name] if materialName in processedMaterialList: # already defined pass elif lastProcessedMaterial == materialName: # prevent endless loop if not totallyDefined: raise ValueError("Material '%s' not totally defined") else: thickness = inputMaterialDict.get(Thickness, 1.0) density = inputMaterialDict.get(Density, 1.0) comment = inputMaterialDict.get(Comment, "") if not len(comment): comment = "" compoundList = inputMaterialDict[CompoundList] fractionList = inputMaterialDict[CompoundFraction] if not hasattr(fractionList, "__getitem__"): compoundList = [compoundList] fractionList = [fractionList] composition = {} for n in range(len(compoundList)): composition[compoundList[n]] = float(fractionList[n]) # check the composition is expressed in terms of elements # and not in terms of other undefined materials totallyDefined = True for element in composition: #check if it can be understood if not len(elementsInstance.getComposition(element)): # compound not understood # probably we have a material defined in terms of other material totallyDefined = False if totallyDefined: try: fisxMaterial = Material(materialName, density=float(density), thickness=float(thickness), comment=comment) fisxMaterial.setComposition(composition) fisxMaterials.append(fisxMaterial) except: text = "Error defining material %s" % \ materialName text += "\n" + "%s" % (sys.exc_info()[1]) raise TypeError(text) processedMaterialList.append(materialName) lastProcessedMaterial = materialName return fisxMaterials
def _getFisxMaterials(fitConfiguration): """ Given a PyMca fir configuration, return the list of fisx materials to be used by the library for calculation purposes. """ global xcom if xcom is None: xcom = getElementsInstance() # define all the needed materials inputMaterialDict = fitConfiguration.get("materials", {}) inputMaterialList = list(inputMaterialDict.keys()) nMaterials = len(inputMaterialList) fisxMaterials = [] processedMaterialList = [] nIter = 10000 while (len(processedMaterialList) != nMaterials) and (nIter > 0): nIter -= 1 for i in range(nMaterials): materialName = inputMaterialList[i] if materialName in processedMaterialList: # already defined pass else: thickness = inputMaterialDict[materialName].get("Thickness", 1.0) density = inputMaterialDict[materialName].get("Density", 1.0) comment = inputMaterialDict[materialName].get("Comment", "") if type(comment) in [type([])]: # the user may have put a comma in the comment leading to # misinterpretation of the string as a list if len(comment) == 0: comment = "" elif len(comment) == 1: comment = comment[0] else: actualComment = comment[0] for commentPiece in comment[1:]: actualComment = actualComment + "," + commentPiece comment = actualComment if not len(comment): comment = "" compoundList = inputMaterialDict[materialName]["CompoundList"] fractionList = inputMaterialDict[materialName]["CompoundFraction"] if not hasattr(fractionList, "__getitem__"): compoundList = [compoundList] fractionList = [fractionList] composition = {} for n in range(len(compoundList)): composition[compoundList[n]] = fractionList[n] # check the composition is expressed in terms of elements # and not in terms of other undefined materials totallyDefined = True for element in composition: # check if it can be understood if element in processedMaterialList: # already defined continue elif not len(xcom.getComposition(element)): # compound not understood # probably we have a material defined in terms of other material totallyDefined = False if totallyDefined: try: fisxMaterial = Material(materialName, density=density, thickness=thickness, comment=comment) fisxMaterial.setComposition(composition) fisxMaterials.append(fisxMaterial) except: if len(materialName): raise TypeError("Error defining material <%s>" % materialName) processedMaterialList.append(materialName) if len(processedMaterialList) < nMaterials: txt = "Undefined materials. " for material in inputMaterialList: if material not in processedMaterialList: txt += "\nCannot define material <%s>\nComposition " % material compoundList = inputMaterialDict[material]["CompoundList"] fractionList = inputMaterialDict[material]["CompoundFraction"] for compound in compoundList: if not len(xcom.getComposition(compound)): if compound not in processedMaterialList: if compound + " " in processedMaterialList: txt += "contains <%s> (defined as <%s>), " % (compound, compound + " ") else: txt += "contains <%s> (undefined)," % compound print(txt) raise KeyError(txt) return fisxMaterials