def dSpacing(self): """ Returns the lattice spacing d in A. :return: Lattice spacing. """ # Retrieve lattice spacing d from xraylib in Angstrom. d_spacing = xraylib.Crystal_dSpacing(self._crystal, self.millerH(), self.millerK(), self.millerL()) return d_spacing
def calc_rocking_curve_shift(crystal='Si', energy=8, h=1, k=1, l=1, rel_angle=1, debye_temp_factor=1): ''' Calculates the angular shift of the Rocking Curve. It uses xraylib. Parameters: - crystal: crystal material. [str] - energy: energy in keV. [float] - h, k, l: Miller indexes. [int] - rel_angle: relative angle [float] - debye_temp_factor: Debye Temperature Factor. [float] Returns: - w0: Angular shift of the Rocking Curve in rad. [float] References: Elements of modern X-ray physics / Jens Als-Nielsen, Des McMorrow – 2nd ed. Cap. 6. ''' # Function: def calc_g(d, r0, Vc, F): return abs((2 * d * d * r0 / (Vc)) * F) # Calculating rocking curve shift: cryst = xraylib.Crystal_GetCrystal(crystal) bragg = xraylib.Bragg_angle(cryst, energy, h, k, l) r0 = physical_constants['classical electron radius'][0] F0 = xraylib.Crystal_F_H_StructureFactor(cryst, energy, 0, 0, 0, debye_temp_factor, rel_angle) d = 1e-10 * xraylib.Crystal_dSpacing(cryst, h, k, l) V = 1e-30 * cryst['volume'] g0 = calc_g(d, r0, V, F0) w0 = (g0 / (np.pi)) * np.tan(bragg) return w0
def test_crystal_diffraction(self): crystals_list = xraylib.Crystal_GetCrystalsList() self.assertEqual(len(crystals_list), 38) for crystal_name in crystals_list: cs = xraylib.Crystal_GetCrystal(crystal_name) self.assertEqual(crystal_name, cs['name']) with self.assertRaises(ValueError): cs = xraylib.Crystal_GetCrystal(None) with self.assertRaises(ValueError): cs = xraylib.Crystal_GetCrystal("non-existent-crystal") cs = xraylib.Crystal_GetCrystal("Diamond") cs_copy = xraylib.Crystal_MakeCopy(cs) with self.assertRaises(ValueError): xraylib.Crystal_AddCrystal(cs) with self.assertRaises(ValueError): xraylib.Crystal_AddCrystal(cs_copy) cs_copy['name'] = "Diamond-copy" xraylib.Crystal_AddCrystal(cs_copy) cs_copy['name'] = 20012016 with self.assertRaises(TypeError): xraylib.Crystal_AddCrystal(cs_copy) cs_copy['name'] = "Diamond-copy" cs_copy['atom'] = list() with self.assertRaises(TypeError): xraylib.Crystal_AddCrystal(cs_copy) cs_copy['atom'] = (25, "jkewjfpwejffj", None, ) with self.assertRaises(TypeError): xraylib.Crystal_AddCrystal(cs_copy) del cs_copy['atom'] with self.assertRaises(KeyError): xraylib.Crystal_AddCrystal(cs_copy) crystals_list = xraylib.Crystal_GetCrystalsList() self.assertEqual(len(crystals_list), 39) for crystal_name in crystals_list: cs = xraylib.Crystal_GetCrystal(crystal_name) self.assertEqual(crystal_name, cs['name']) current_ncrystals = len(crystals_list) for i in range(xraylib.CRYSTALARRAY_MAX): cs_copy = xraylib.Crystal_MakeCopy(cs) cs_copy['name'] = "Diamond copy {}".format(i) if current_ncrystals < xraylib.CRYSTALARRAY_MAX: xraylib.Crystal_AddCrystal(cs_copy) current_ncrystals = current_ncrystals + 1 self.assertEqual(len(xraylib.Crystal_GetCrystalsList()), current_ncrystals) else: with self.assertRaises(RuntimeError): xraylib.Crystal_AddCrystal(cs_copy) self.assertEqual(len(xraylib.Crystal_GetCrystalsList()), xraylib.CRYSTALARRAY_MAX) cs = xraylib.Crystal_GetCrystal("Diamond") # Bragg angle angle = xraylib.Bragg_angle(cs, 10.0, 1, 1, 1) self.assertAlmostEqual(angle, 0.3057795845795849) with self.assertRaises(TypeError): angle = xraylib.Bragg_angle(None, 10.0, 1, 1, 1) with self.assertRaises(ValueError): angle = xraylib.Bragg_angle(cs, -10.0, 1, 1, 1) with self.assertRaises(TypeError): angle = xraylib.Bragg_angle(cs, 1, 1, 1) # Q_scattering_amplitude tmp = xraylib.Q_scattering_amplitude(cs, 10.0, 1, 1, 1, math.pi/4.0) self.assertAlmostEqual(tmp, 0.19184445408324474) tmp = xraylib.Q_scattering_amplitude(cs, 10.0, 0, 0, 0, math.pi/4.0) self.assertEqual(tmp, 0.0) # Atomic factors (f0, f_prime, f_prime2) = xraylib.Atomic_Factors(26, 10.0, 1.0, 10.0) self.assertAlmostEqual(f0, 65.15) self.assertAlmostEqual(f_prime, -0.22193271025027966) self.assertAlmostEqual(f_prime2, 22.420270655080493) with self.assertRaises(ValueError): (f0, f_prime, f_prime2) = xraylib.Atomic_Factors(-10, 10.0, 1.0, 10.0) # unit cell volume tmp = xraylib.Crystal_UnitCellVolume(cs) self.assertAlmostEqual(tmp, 45.376673902751) # crystal dspacing tmp = xraylib.Crystal_dSpacing(cs, 1, 1, 1) self.assertAlmostEqual(tmp, 2.0592870875248344) del cs
def new_bragg(cls, DESCRIPTOR="Graphite", H_MILLER_INDEX=0, K_MILLER_INDEX=0, L_MILLER_INDEX=2, TEMPERATURE_FACTOR=1.0, E_MIN=5000.0, E_MAX=15000.0, E_STEP=100.0, SHADOW_FILE="bragg.dat"): """ SHADOW preprocessor for crystals - python+xraylib version -""" # retrieve physical constants needed codata = scipy.constants.codata.physical_constants codata_e2_mc2, tmp1, tmp2 = codata["classical electron radius"] # or, hard-code them # In [179]: print("codata_e2_mc2 = %20.11e \n" % codata_e2_mc2 ) # codata_e2_mc2 = 2.81794032500e-15 fileout = SHADOW_FILE descriptor = DESCRIPTOR hh = int(H_MILLER_INDEX) kk = int(K_MILLER_INDEX) ll = int(L_MILLER_INDEX) temper = float(TEMPERATURE_FACTOR) emin = float(E_MIN) emax = float(E_MAX) estep = float(E_STEP) # # end input section, start calculations # f = open(fileout, 'wt') cryst = xraylib.Crystal_GetCrystal(descriptor) volume = cryst['volume'] #test crystal data - not needed itest = 1 if itest: if (cryst == None): sys.exit(1) print(" Unit cell dimensions are %f %f %f" % (cryst['a'], cryst['b'], cryst['c'])) print(" Unit cell angles are %f %f %f" % (cryst['alpha'], cryst['beta'], cryst['gamma'])) print(" Unit cell volume is %f A^3" % volume) print(" Atoms at:") print(" Z fraction X Y Z") for i in range(cryst['n_atom']): atom = cryst['atom'][i] print(" %3i %f %f %f %f" % (atom['Zatom'], atom['fraction'], atom['x'], atom['y'], atom['z'])) print(" ") volume = volume * 1e-8 * 1e-8 * 1e-8 # in cm^3 #flag ZincBlende f.write("%i " % 0) #1/V*electronRadius f.write("%e " % ((1e0 / volume) * (codata_e2_mc2 * 1e2))) #dspacing dspacing = xraylib.Crystal_dSpacing(cryst, hh, kk, ll) f.write("%e " % (dspacing * 1e-8)) f.write("\n") #Z's atom = cryst['atom'] f.write("%i " % atom[0]["Zatom"]) f.write("%i " % atom[-1]["Zatom"]) f.write("%e " % temper) # temperature parameter f.write("\n") ga = (1e0+0j) + cmath.exp(1j*cmath.pi*(hh+kk)) \ + cmath.exp(1j*cmath.pi*(hh+ll)) \ + cmath.exp(1j*cmath.pi*(kk+ll)) gb = ga * cmath.exp(1j * cmath.pi * 0.5 * (hh + kk + ll)) ga_bar = ga.conjugate() gb_bar = gb.conjugate() f.write("(%20.11e,%20.11e ) \n" % (ga.real, ga.imag)) f.write("(%20.11e,%20.11e ) \n" % (ga_bar.real, ga_bar.imag)) f.write("(%20.11e,%20.11e ) \n" % (gb.real, gb.imag)) f.write("(%20.11e,%20.11e ) \n" % (gb_bar.real, gb_bar.imag)) zetas = numpy.array([atom[0]["Zatom"], atom[-1]["Zatom"]]) for zeta in zetas: xx01 = 1e0 / 2e0 / dspacing xx00 = xx01 - 0.1 xx02 = xx01 + 0.1 yy00 = xraylib.FF_Rayl(int(zeta), xx00) yy01 = xraylib.FF_Rayl(int(zeta), xx01) yy02 = xraylib.FF_Rayl(int(zeta), xx02) xx = numpy.array([xx00, xx01, xx02]) yy = numpy.array([yy00, yy01, yy02]) fit = numpy.polyfit(xx, yy, 2) #print "zeta: ",zeta #print "z,xx,YY: ",zeta,xx,yy #print "fit: ",fit[::-1] # reversed coeffs #print "fit-tuple: ",(tuple(fit[::-1].tolist())) # reversed coeffs #print("fit-tuple: %e %e %e \n" % (tuple(fit[::-1].tolist())) ) # reversed coeffs f.write("%e %e %e \n" % (tuple(fit[::-1].tolist()))) # reversed coeffs npoint = int((emax - emin) / estep + 1) f.write(("%i \n") % npoint) for i in range(npoint): energy = (emin + estep * i) f1a = xraylib.Fi(int(zetas[0]), energy * 1e-3) f2a = xraylib.Fii(int(zetas[0]), energy * 1e-3) f1b = xraylib.Fi(int(zetas[1]), energy * 1e-3) f2b = xraylib.Fii(int(zetas[1]), energy * 1e-3) out = numpy.array([energy, f1a, abs(f2a), f1b, abs(f2b)]) f.write(("%20.11e %20.11e %20.11e \n %20.11e %20.11e \n") % (tuple(out.tolist()))) f.close() print("File written to disk: %s" % fileout)
def bragg(): """ SHADOW preprocessor for crystals - python+xraylib version -""" # retrieve physical constants needed codata = scipy.constants.codata.physical_constants codata_e2_mc2, tmp1, tmp2 = codata["classical electron radius"] # or, hard-code them # In [179]: print("codata_e2_mc2 = %20.11e \n" % codata_e2_mc2 ) # codata_e2_mc2 = 2.81794032500e-15 print("bragg: SHADOW preprocessor for crystals - python+xraylib version") fileout = raw_input("Name of output file : ") f = open(fileout, 'wb') print(" bragg (python) only works now for ZincBlende Cubic structures. ") print(" Valid descriptor are: ") print(" Si (alternatiovely Si_NIST, Si2) ") print(" Ge") print(" Diamond") print(" GaAs, GaSb, GaP") print(" InAs, InP, InSb") print(" SiC") descriptor = raw_input("Name of crystal descriptor : ") cryst = xraylib.Crystal_GetCrystal(descriptor) #test crystal data - not needed itest = 1 if itest: if (cryst == None): sys.exit(1) print " Unit cell dimensions are %f %f %f" % (cryst['a'],cryst['b'],cryst['c']) print " Unit cell angles are %f %f %f" % (cryst['alpha'],cryst['beta'],cryst['gamma']) volume = cryst['volume'] print " Unit cell volume is %f" % volume volume = volume*1e-8*1e-8*1e-8 # in cm^3 print " Atoms at:" print " Z fraction X Y Z" for i in range(cryst['n_atom']): atom = cryst['atom'][i] print " %3i %f %f %f %f" % (atom['Zatom'], atom['fraction'], atom['x'], atom['y'], atom['z']) print " " print("Miller indices of crystal plane of reflection.") miller = raw_input("H K L: ") miller = miller.split() hh = int(miller[0]) kk = int(miller[1]) ll = int(miller[2]) #flag ZincBlende f.write( "%i " % 0) #1/V*electronRadius f.write( "%e " % ((1e0/volume)*(codata_e2_mc2*1e2)) ) #dspacing dspacing = xraylib.Crystal_dSpacing(cryst, hh, kk, ll) f.write( "%e " % (dspacing*1e-8) ) f.write( "\n") #Z's atom = cryst['atom'] f.write( "%i " % atom[0]["Zatom"] ) f.write( "%i " % atom[7]["Zatom"] ) temper = raw_input("Temperature (Debye-Waller) factor (set 1 for default): ") temper = float(temper) f.write( "%e " % temper ) # temperature parameter f.write( "\n") ga = (1e0+0j) + cmath.exp(1j*cmath.pi*(hh+kk)) \ + cmath.exp(1j*cmath.pi*(hh+ll)) \ + cmath.exp(1j*cmath.pi*(kk+ll)) gb = ga * cmath.exp(1j*cmath.pi*0.5*(hh+kk+ll)) ga_bar = ga.conjugate() gb_bar = gb.conjugate() f.write( "(%20.11e,%20.11e ) \n" % (ga.real, ga.imag) ) f.write( "(%20.11e,%20.11e ) \n" % (ga_bar.real, ga_bar.imag) ) f.write( "(%20.11e,%20.11e ) \n" % (gb.real, gb.imag) ) f.write( "(%20.11e,%20.11e ) \n" % (gb_bar.real, gb_bar.imag) ) zetas = numpy.array([atom[0]["Zatom"],atom[7]["Zatom"]]) for zeta in zetas: xx01 = 1e0/2e0/dspacing xx00 = xx01-0.1 xx02 = xx01+0.1 yy00= xraylib.FF_Rayl(int(zeta),xx00) yy01= xraylib.FF_Rayl(int(zeta),xx01) yy02= xraylib.FF_Rayl(int(zeta),xx02) xx = numpy.array([xx00,xx01,xx02]) yy = numpy.array([yy00,yy01,yy02]) fit = numpy.polyfit(xx,yy,2) #print "zeta: ",zeta #print "z,xx,YY: ",zeta,xx,yy #print "fit: ",fit[::-1] # reversed coeffs #print "fit-tuple: ",(tuple(fit[::-1].tolist())) # reversed coeffs #print("fit-tuple: %e %e %e \n" % (tuple(fit[::-1].tolist())) ) # reversed coeffs f.write("%e %e %e \n" % (tuple(fit[::-1].tolist())) ) # reversed coeffs emin = raw_input("minimum photon energy (eV): ") emin = float(emin) emax = raw_input("maximum photon energy (eV): ") emax = float(emax) estep = raw_input("energy step (eV): ") estep = float(estep) npoint = int( (emax - emin)/estep + 1 ) f.write( ("%i \n") % npoint) for i in range(npoint): energy = (emin+estep*i) f1a = xraylib.Fi(int(zetas[0]),energy*1e-3) f2a = xraylib.Fii(int(zetas[0]),energy*1e-3) f1b = xraylib.Fi(int(zetas[1]),energy*1e-3) f2b = xraylib.Fii(int(zetas[1]),energy*1e-3) out = numpy.array([energy,f1a,abs(f2a),f1b,abs(f2b)]) f.write( ("%20.11e %20.11e %20.11e \n %20.11e %20.11e \n") % ( tuple(out.tolist()) ) ) f.close() print("File written to disk: %s" % fileout) return None
# define miller indices, distances and photon energy in eV # hh = 1 kk = 1 ll = 1 d1 = 3000.0 d2 = 3000.0 alpha = 5.0 * numpy.pi / 180.0 # asymmetry angle in rad crystal_name = "Si" photon_energy_ev = 10000.0 # # get crystal info from xraylib # cryst = xraylib.Crystal_GetCrystal(crystal_name) dspacing = xraylib.Crystal_dSpacing(cryst,hh,kk,ll ) #sin_theta = (tocm/(photon_energy_ev*2.0*dspacing*1e-8)); #rt=2*p*q/(p+q)/sin_theta; #rs=2*p*q*sin_theta/(p+q); theta=numpy.arcsin(tocm/(photon_energy_ev*2.0*dspacing*1e-8)) t1 = theta + alpha t2 = theta - alpha #calculations s1 = numpy.sin(t1) s2 = numpy.sin(t2) s1_2 = s1*s1
def calc_Darwin_curve(delta_theta=np.linspace(-0.00015, 0.00015, 5000), crystal='Si', energy=8, h=1, k=1, l=1, rel_angle=1, debye_temp_factor=1, use_correction=True, save_txt=True, save_fig=True, filename_to_save='Darwin_curve'): ''' Calculates the Darwin curve. It does not considers absortion. Valid for s-polarization only. Parameters: - delta_theta: array containing values of (Theta - Theta_Bragg) in rad. [array] - crystal: crystal material. [str] - energy: energy in keV. [float] - h, k, l: Miller indexes. [int] - rel_angle: relative angle [float] - debye_temp_factor: Debye Temperature Factor. [float] - use_correction: if True, considers the corrected Bragg angle due to refraction. [boolean] - save_txt: if True, saves the Darwin Curve in a .txt file. [boolean] - save_fig: if True, saves a figure with the Darwin Curve in .png. [boolean] - filename_to_save: name to save the figure and the .txt file. [string] Returns: - delta_theta: Array containing values of (Theta - Theta_Bragg) in rad. [array] - R: Intensity reflectivity array. [array] - zeta_total: Total Darwin width (delta_lambda/lambda). [float] - zeta_FWHM: Darwin width FWHM (delta_lambda/lambda). [float] - w_total: Total Angular Darwin width (delta_Theta) in rad. [float] - w_FWHM: Angular Darwin width FWHM (delta_Theta) in rad. [float] - w0: Angular shift of the Rocking Curve in rad. [float] References: Elements of modern X-ray physics / Jens Als-Nielsen, Des McMorrow – 2nd ed. Cap. 6. ''' # Functions: def calc_g(d, r0, Vc, F): return abs((2 * d * d * r0 / (Vc)) * F) def calc_xc(zeta, g, g0): return np.pi * zeta / g - g0 / g def calc_zeta_total(d, r0, Vc, F): return (4 / np.pi) * (d) * (d) * (r0 * abs(F) / Vc) def Darwin_curve(xc): R = [] for x in xc: if (x >= 1): r = (x - np.sqrt(x * x - 1)) * (x - np.sqrt(x * x - 1)) if (x <= 1): r = 1 if (x <= -1): r = (x + np.sqrt(x * x - 1)) * (x + np.sqrt(x * x - 1)) R.append(r) return np.array(R) # Calculating Darwin curve: cryst = xraylib.Crystal_GetCrystal(crystal) bragg = xraylib.Bragg_angle(cryst, energy, h, k, l) zeta = delta_theta / np.tan(bragg) r0 = physical_constants['classical electron radius'][0] FH = xraylib.Crystal_F_H_StructureFactor(cryst, energy, h, k, l, debye_temp_factor, rel_angle) F0 = xraylib.Crystal_F_H_StructureFactor(cryst, energy, 0, 0, 0, debye_temp_factor, rel_angle) d = 1e-10 * xraylib.Crystal_dSpacing(cryst, h, k, l) V = 1e-30 * cryst['volume'] g = calc_g(d, r0, V, FH) g0 = calc_g(d, r0, V, F0) xc = calc_xc(zeta, g, g0) R = Darwin_curve(xc) zeta_total = calc_zeta_total(d, r0, V, FH) zeta_FWHM = (3 / (2 * np.sqrt(2))) * zeta_total w_total = zeta_total * np.tan(bragg) w_FWHM = (3 / (2 * np.sqrt(2))) * w_total w0 = (g0 / (np.pi)) * np.tan(bragg) # Correcting curve offset (due to refraction): if (use_correction): delta_theta = delta_theta - w0 # Saving .txt file: if (save_txt): filename = filename_to_save + '.txt' with open(filename, 'w') as f: f.write('#Delta_Theta[rad] Intensity_Reflectivity \n') for i in range(len(R)): f.write('%.6E\t%.6E \n' % (delta_theta[i], R[i])) # Plotting Graph: plt.figure() plt.plot(delta_theta, R, linewidth=1.8, color='black') plt.fill_between(delta_theta, R, alpha=0.9, color='C0') plt.ylabel('Intensity reflectivity', fontsize=13) plt.xlabel('$\Delta$' + '$\Theta$' + ' [rad]', fontsize=13) plt.xscale('linear') plt.yscale('linear') plt.minorticks_on() plt.ticklabel_format(style='sci', axis='x', scilimits=(0, 0)) plt.tick_params(which='both', axis='both', direction='in', right=True, top=True, labelsize=12) plt.grid(which='both', alpha=0.2) plt.tight_layout() textstr = '\n'.join((r'$\zeta_{total}=$%.4E' % (zeta_total, ), r'$\zeta_{FWHM}=$%.4E' % (zeta_FWHM, ), r'$\omega_{total}=$%.4E rad' % (w_total, ), r'$\omega_{FWHM}=$%.4E rad' % (w_FWHM, ))) props = dict(boxstyle='round', facecolor='wheat', alpha=0.5) # wheat # gray plt.text(0.05, 0.95, textstr, transform=plt.gca().transAxes, fontsize=10, verticalalignment='top', bbox=props) plt.show() if (save_fig): plt.savefig(filename_to_save + '.png', dpi=600) return delta_theta, R, zeta_total, zeta_FWHM, w_total, w_FWHM, w0
def calcTemperatureFactor(temperature, crystal='Si', debyeTemperature=644.92, millerIndex=[1, 1, 1], atomicMass=28.09, dSpacing=3.1354162886330583): """ Calculates the (Debye) temperature factor for single crystals. Parameters ---------- temperature : float Crystal temperature in Kelvin (positive number). crystal : str Crystal single-element symbol (e.g. Si, Ge, ...). debyeTemperature : float Debye temperature of the crystal material in Kelvin. millerIndex : array-like (1D), optional Miller indexes of the crystal orientation. For use with xraylib only. atomicMass : float, optional. Atomic mass of the crystal element (amu unit). if atomicMass == 0, get from xraylib. dSpacing : float, optional. dSpacing in Angstroms, given the crystal and millerIndex . if dSpacing == 0, get from xraylib. Returns: -------- temperatureFactor : float Examples: --------- ### using xraylib: >>> calcTemperatureFactor(80, crystal='Si', millerIndex=[3,1,1], debyeTemperature=644.92, dSpacing=0, atomicMass=0) 0.983851994268226 ### forcing it to use given dSpacing and atomicMass: >>> calcTemperatureFactor(80, crystal='Si', millerIndex=[1,1,1], debyeTemperature=644.92, atomicMass=28.09, dSpacing=3.1354163) 0.9955698950510736 References: ----------- [1]: A. Freund, Nucl. Instrum. and Meth. 213 (1983) 495-501 [2]: M. Sanchez del Rio and R. J. Dejus, "Status of XOP: an x-ray optics software toolkit", SPIE proc. vol. 5536 (2004) pp.171-174 """ def debyeFunc(x): return x / (np.exp(-x) - 1) def debyePhi(y): from scipy.integrate import quad integral = quad(lambda x: debyeFunc(x), 0, y)[0] return (1 / y) * integral planck = 6.62607015e-34 # codata.Planck Kb = 1.380649e-23 # codata.Boltzmann atomicMassTokg = 1.6605390666e-27 # codata.atomic_mass try: import xraylib h, k, l = millerIndex crystalDict = xraylib.Crystal_GetCrystal(crystal) if (dSpacing == 0): dSpacing = xraylib.Crystal_dSpacing(crystalDict, h, k, l) if (atomicMass == 0): atomicMass = xraylib.AtomicWeight( xraylib.SymbolToAtomicNumber(crystal)) except: print( "xraylib not available. Please give dSpacing and atomicMass manually." ) if ((dSpacing == 0) or (atomicMass == 0)): return np.nan atomicMass *= atomicMassTokg # converting to [kg] dSpacing *= 1e-10 # converting to [m] x = debyeTemperature / (-1 * temperature) # invert temperature sign (!!!) B0 = (3 * planck**2) / (2 * Kb * debyeTemperature * atomicMass) BT = 4 * B0 * debyePhi(x) / x ratio = 1 / (2 * dSpacing) M = (B0 + BT) * ratio**2 temperatureFactor = np.exp(-M) return temperatureFactor