Exemple #1
0
def calc_Bragg_angle(crystal='Si', energy=8, h=1, k=1, l=1, corrected=False):
    '''
    Calculates Bragg angle using xraylib.
    
    Parameters:
        
    - crystal: crystal material. [str]
    - energy: energy in keV. [float]
    - h, k, l: Miller indexes. [int]
    
    Returns:
    
    - bragg: Bragg angle in rad. [float] 
    
    '''

    cryst = xraylib.Crystal_GetCrystal(crystal)

    bragg = xraylib.Bragg_angle(cryst, energy, h, k, l)

    if (corrected):
        w0 = calc_rocking_curve_shift(crystal=crystal,
                                      energy=energy,
                                      h=h,
                                      k=k,
                                      l=l,
                                      rel_angle=1,
                                      debye_temp_factor=1)
        bragg += w0

    return bragg
Exemple #2
0
def calc_Darwin_width(crystal='Si',
                      energy=8,
                      h=1,
                      k=1,
                      l=1,
                      rel_angle=1,
                      debye_temp_factor=1):
    '''
    Calculates Darwin width and intrinsic resolution for p and s polarizations. 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:
    
    - dw_s: Angular Darwin width for s polarization in rad. [float] 
    - dw_p: Angular Darwin width for p polarization in rad. [float] 
    - resolution_s: Intrinsic resolution for s polarization. [float] 
    - resolution_p: Intrinsic resolution for p polarization. [float] 
    
    References:
        
    A simple formula to calculate the x-ray flux after a double-crystal monochromator - M. S. del Rio; O. MATHON.
    
    '''

    cryst = xraylib.Crystal_GetCrystal(crystal)

    bragg = xraylib.Bragg_angle(cryst, energy, h, k, l)

    FH = xraylib.Crystal_F_H_StructureFactor(cryst, energy, h, k, l,
                                             debye_temp_factor, rel_angle)

    FHbar = xraylib.Crystal_F_H_StructureFactor(cryst, energy, -h, -k, -l,
                                                debye_temp_factor, rel_angle)

    C = abs(np.cos(2 * bragg))

    dw_p = 1e10 * 2 * C * (xraylib.R_E / cryst['volume']) * (
        xraylib.KEV2ANGST * xraylib.KEV2ANGST / (energy * energy)) * np.sqrt(
            abs(FH * FHbar)) / np.pi / np.sin(2 * bragg)

    dw_s = 1e10 * 2 * (xraylib.R_E / cryst['volume']) * (
        xraylib.KEV2ANGST * xraylib.KEV2ANGST / (energy * energy)) * np.sqrt(
            abs(FH * FHbar)) / np.pi / np.sin(2 * bragg)

    resolution_p = dw_p / np.tan(bragg)

    resolution_s = dw_s / np.tan(bragg)

    return dw_s, dw_p, resolution_s, resolution_p
Exemple #3
0
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 angleBragg(self, energy):
        """
        Returns the Bragg angle in rad for a given energy.
        :param energy: Energy to calculate the Bragg angle for.
        :return: Bragg angle.
        """
        energy_in_kev = energy / 1000.0

        # Retrieve bragg angle from xraylib.
        angle_bragg = xraylib.Bragg_angle(self._crystal, energy_in_kev,
                                          self.millerH(), self.millerK(),
                                          self.millerL())
        return angle_bragg
    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
Exemple #6
0
                                                cryst['gamma']))
print("Si unit cell volume is {}".format(cryst['volume']))
print("Si atoms at:")
print("   Z  fraction    X        Y        Z")
for i in range(cryst['n_atom']):
    atom = cryst['atom'][i]
    print("  {} {} {} {} {}".format(atom['Zatom'], atom['fraction'], atom['x'],
                                    atom['y'], atom['z']))
print("")

print("Si111 at 8 KeV. Incidence at the Bragg angle:")
energy = 8
debye_temp_factor = 1.0
rel_angle = 1.0

bragg = xraylib.Bragg_angle(cryst, energy, 1, 1, 1)
print("  Bragg angle: Rad: {} Deg: {}".format(bragg, bragg * 180 / math.pi))

q = xraylib.Q_scattering_amplitude(cryst, energy, 1, 1, 1, rel_angle)
print("  Q Scattering amplitude: {}".format(q))

#notice the 3 return values!!!
f0, fp, fpp = xraylib.Atomic_Factors(14, energy, q, debye_temp_factor)
print("  Atomic factors (Z = 14) f0, fp, fpp: {}, {}, i*{}".format(
    f0, fp, fpp))

FH = xraylib.Crystal_F_H_StructureFactor(cryst, energy, 1, 1, 1,
                                         debye_temp_factor, rel_angle)
print("  FH(1,1,1) structure factor: ({}, {})".format(FH.real, FH.imag))

F0 = xraylib.Crystal_F_H_StructureFactor(cryst, energy, 0, 0, 0,
Exemple #7
0
    def apply(self):

        if not self._input_available:
            raise Exception("AlignmentTool: Input data not available!\n")

        energy_in_kev = self.BASE_ENERGY / 1000.0

        outgoing_bunch = PolarizedPhotonBunch([])

        x_axis = Vector(1, 0, 0)
        neg_x_axis = Vector(-1, 0, 0)

        # Retrieve Bragg angle from xraylib.
        angle_bragg = xraylib.Bragg_angle(self.CRYSTAL, energy_in_kev,
                                          self.MILLER_H, self.MILLER_K,
                                          self.MILLER_L)

        # TODO: change rotation using the crystalpy tool to get full alignment.
        for i in range(self.incoming_bunch.getNumberOfPhotons()):
            polarized_photon = self.incoming_bunch.getPhotonIndex(i)

            if self.MODE == 0:  # ray-to-crystal
                rotated_vector = polarized_photon.unitDirectionVector().\
                    rotateAroundAxis(neg_x_axis, angle_bragg + self.ALPHA_X*np.pi/180)

            elif self.MODE == 1:  # crystal-to-ray
                rotated_vector = polarized_photon.unitDirectionVector(). \
                    rotateAroundAxis(neg_x_axis, angle_bragg - self.ALPHA_X*np.pi/180)

            else:
                raise Exception(
                    "AlignmentTool: The alignment mode could not be interpreted correctly!\n"
                )

            polarized_photon.setUnitDirectionVector(rotated_vector)
            outgoing_bunch.addPhoton(polarized_photon)

        # Dump data to file if requested.
        if self.DUMP_TO_FILE:

            print("AlignmentTool: Writing data in {file}...\n".format(
                file=self.FILE_NAME))

            with open(self.FILE_NAME, "w") as file:
                try:
                    file.write(
                        "#S 1 photon bunch\n"
                        "#N 9\n"
                        "#L  Energy [eV]  Vx  Vy  Vz  S0  S1  S2  S3  CircularPolarizationDegree\n"
                    )
                    file.write(outgoing_bunch.toString())
                    file.close()
                    print("File written to disk: %s \n" % self.FILE_NAME)

                except:
                    raise Exception(
                        "AlignmentTool: The data could not be dumped onto the specified file!\n"
                    )

        self.send("photon bunch", outgoing_bunch)
        print("AlignmentTool: Photon bunch aligned.\n")
Exemple #8
0
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