Source code for ncempy.edstomo.CharacteristicEmission

from io import StringIO
import numpy as np
import pickle
import itertools
import os, sys, shutil

ElamLoaded = False # We only want to load the Elam database once.  Keep track of if that has been done.  False = not yet loaded.
ElamData = []

# For debugging we sometimes want Elam to print out the lines it loaded.
ElamPrint = lambda s: None #print(s)

# Reading the Elam database is time consuming.  This caches the fluorescence data so it is only read once per program
#  load.
ElamFluorescenceLines = {'nodata':1}

[docs]def GetElamFluorescenceLines(ElementName, E=None, I=None): global ElamLoaded, ElamData, ElamFluorescenceLines # Already loaded fluorescence data for this element? if ElementName in ElamFluorescenceLines: # Return the (previously or newly) cached element info. return ElamFluorescenceLines[ElementName] # This is really time consuming, so we also cache it as a pickle file. try: ElementXRayLines = pickle.load(open(os.path.join(os.path.dirname(__file__), 'Elam', ElementName.lower() +'.pickle'), 'rb')) # It was pickled! So cache it in memory and return it. ElamFluorescenceLines[ElementName] = ElementXRayLines return ElementXRayLines except: # It wasn't pickled, no matter. We'll make it now and pickle it at the end of the function. pass # It's not already loaded, so continue with loading it. # Read the entire Elam database into memory. if ElamLoaded == False: fo = open(os.path.join(os.path.dirname(__file__), 'Elam', 'ElamDB12.txt'), "r+") str = fo.read(); fo.close() ElamData = StringIO(str) ElamLoaded = True # Initialize the lists that will contain the line information. LineNamesIUPAC = [] LineNamesSiegbahn = [] Geoms = [] # Make sure we're at the start of the file ElamData.seek(0) # Zoom forward to the element we are looking for. for line in ElamData: if ('Element '+ElementName+' ') in line: break # Pull out the section with the fluorescence lines, which is first. for line in ElamData: # Ignore the lines that aren't the fluorescence info if ('Edge' in line) or ('Lines' in line) or ('CK' in line): continue # When we get to the Photoionization section we are done. if 'Photo' in line: break; # Otherwise, this is a fluorescence line. Add it to our output if it is intense enough to improve the fit q = line.split() if (float(q[3]) > 0.01): LineNamesIUPAC.append(q[0]) LineNamesSiegbahn.append(q[1]) Geoms.append([float(q[2]), float(q[3])]) ElamPrint('Added: ' + line) else: ElamPrint('Ignored (intensity < 1%): ' + line) Geoms = np.array(Geoms) # We are going to use the Siegbahn names, not IUPAC. # Make a dictionary where the key is the line name and the value is an (energy, intensity) tuple. Lines = dict(zip(LineNamesSiegbahn, Geoms)) ElementXRayLines = {} for Series in ['K', 'L', 'M', 'N', 'O']: #Obtain the name strings for only the lines that have names that start with K (or L, or M, whatever Series we are on). ThisSeries = dict([(k, v) for k, v in Lines.items() if k.startswith(Series)]) # If these series is not present, then don't keep it. if len(ThisSeries) == 0: continue # Make this edge in ElementXRayLines ElementXRayLines[Series] = ThisSeries # We've built the fluorescence data for this element. Cache it and pickle it for next time. ElamFluorescenceLines[ElementName] = ElementXRayLines pickle.dump(ElementXRayLines, open(os.path.join(os.path.dirname(__file__), 'Elam', ElementName.lower() + '.pickle'), 'wb')) # And return what we've got. return ElementXRayLines
[docs]def GetWeightedSum(Line, Series): # The key is that the series we want to sum has to have a common prefix. # For example, if Line = 'Ka' then we can sum 'Ka1', 'Ka2' but not 'Kbx' # Get only the lines that match our specific subseries. vals = np.array([Vals for LineName, Vals in Series.items() if Line in LineName]) # Line weights are summed to one for the entire series. Since we often want to weigh a subseries, renormalize. vals[:,1] /= np.sum(vals[:,1]) # Now get a weighted sum: sum(position*relative_intensity) WeightedEnergy = np.sum(vals[:,0]*vals[:,1]) return WeightedEnergy
[docs]def GetFluorescenceLineEnergy(ElementName, Series='K', Line=None): LineData = GetElamFluorescenceLines(ElementName) # If the user requests a "line" which is the series, we will return the weighted sum of all lines in the series (below in the if). if Line == Series: Line = None # If the user specifies a specific line, then we will return its energy. try: if Line in ['Ka', 'Kb', 'La', 'Lb']: # We can make weighted sums of special subseries of lines. return GetWeightedSum(Line, LineData[Series]) elif Line is not None: # Or we can return a specific line which is requested. # print(LineData) return LineData[Series][Line][0] else: # The user doesn't specify a line which means he wants to know the energy of the whole series. return GetWeightedSum(Series, LineData[Series]) except: # If the user asked for a series or line that's not in the database, then we return none. return None
if __name__ == '__main__': print('------------------------------') # print('Fe-K: %s' % GetFluorescenceLineEnergy('Fe')) # print('Al-K: %s' % GetFluorescenceLineEnergy('Al')) # print('Mg-K: %s' % GetFluorescenceLineEnergy('Mg')) # print('Mg-K: %s' % GetFluorescenceLineEnergy('Mg', Series='K')) # print('Mg-K: %s' % GetFluorescenceLineEnergy('Mg', Series='K', Line='K')) # print('Fe-Q: %s' % GetFluorescenceLineEnergy('Fe', Series='Q')) # print('Fe-Ka2: %f' % GetFluorescenceLineEnergy('Fe', Series='K', Line='Ka2')) # print('Fe-Ka1: %f' % GetFluorescenceLineEnergy('Fe', Series='K', Line='Ka1')) # print('Fe-Ka: %f' % GetFluorescenceLineEnergy('Fe', Series='K', Line='Ka')) # print('Fe-Kb: %f' % GetFluorescenceLineEnergy('Fe', Series='K', Line='Kb')) # print('Mn-Ka: %f' % GetFluorescenceLineEnergy('Mn', Series='K', Line='Ka')) # print('Pt-La: %f' % GetFluorescenceLineEnergy('Pt', Series='L', Line='La')) print('S-K: %f' % GetFluorescenceLineEnergy('S', Series='K', Line='K'))