Note

Go to the end to download the full example code.

# Graphene hv scan

Simple workflow for analyzing a photon energy scan data of graphene as simulated from a third nearest neighbor tight binding model. The same workflow can be applied to any photon energy scan.

Import the “fundamental” python libraries for a generic data analysis:

    import numpy as np
    import matplotlib.pyplot as plt

Instead of loading the file as for example:

    # from navarp.utils import navfile
    # file_name = r"nxarpes_simulated_cone.nxs"
    # entry = navfile.load(file_name)

Here we build the simulated graphene signal with a dedicated function defined just for this purpose:

    from navarp.extras.simulation import get_tbgraphene_hv

    entry = get_tbgraphene_hv(
        scans=np.arange(90, 150, 2),
        angles=np.linspace(-7, 7, 300),
        ebins=np.linspace(-3.3, 0.4, 450),
        tht_an=-18,
    )

## Plot a single analyzer image at scan = 90

First I have to extract the isoscan from the entry, so I use the isoscan method of entry:

    iso0 = entry.isoscan(scan=90)

Then to plot it using the ‘show’ method of the extracted iso0:

    iso0.show(yname='ekin')

    <matplotlib.collections.QuadMesh object at 0x78094713f4d0>

Or by string concatenation, directly as:

    entry.isoscan(scan=90).show(yname='ekin')

    <matplotlib.collections.QuadMesh object at 0x780946e7e710>

## Fermi level determination

The initial guess for the binding energy is: ebins = ekins - (hv - work_fun). However, the better way is to proper set the Fermi level first and then derives everything form it. In this case the Fermi level kinetic energy is changing along the scan since it is a photon energy scan. So to set the Fermi level I have to give an array of values corresponding to each photon energy. By definition I can give:

    efermis = entry.hv - entry.analyzer.work_fun
    entry.set_efermi(efermis)

Or I can use a method for its detection, but in this case, it is important to give a proper energy range for each photon energy. For example for each photon a good range is within 0.4 eV around the photon energy minus the analyzer work function:

    energy_range = (
        (entry.hv[:, None] - entry.analyzer.work_fun) +
        np.array([-0.4, 0.4])[None, :])

    entry.autoset_efermi(energy_range=energy_range)

    scan(eV)  efermi(eV)  FWHM(meV)  new hv(eV)
    90.0000  85.4002  59.0  90.0002
    92.0000  87.4003  57.3  92.0003
    94.0000  89.3998  58.2  93.9998
    96.0000  91.4003  58.3  96.0003
    98.0000  93.4005  58.2  98.0005
    100.0000  95.3998  59.3  99.9998
    102.0000  97.4001  58.7  102.0001
    104.0000  99.4000  59.3  104.0000
    106.0000  101.4002  59.8  106.0002
    108.0000  103.4004  58.1  108.0004
    110.0000  105.4002  58.6  110.0002
    112.0000  107.4001  59.4  112.0001
    114.0000  109.4002  59.2  114.0002
    116.0000  111.4005  58.2  116.0005
    118.0000  113.4003  59.2  118.0003
    120.0000  115.4005  59.4  120.0005
    122.0000  117.4000  58.1  122.0000
    124.0000  119.4007  58.5  124.0007
    126.0000  121.4006  59.3  126.0006
    128.0000  123.4005  58.2  128.0005
    130.0000  125.3999  59.5  129.9999
    132.0000  127.4003  59.1  132.0003
    134.0000  129.4004  58.3  134.0004
    136.0000  131.4004  59.1  136.0004
    138.0000  133.4004  58.9  138.0004
    140.0000  135.4002  59.7  140.0002
    142.0000  137.4008  57.8  142.0008
    144.0000  139.4009  58.5  144.0009
    146.0000  141.4006  59.3  146.0006
    148.0000  143.4005  58.6  148.0005

In both cases the binding energy and the photon energy will be updated consistently. Note that the work function depends on the beamline or laboratory. If not specified is 4.5 eV.

To check the Fermi level detection I can have a look on each photon energy. Here I show only the first 10 photon energies:

    for scan_i in range(10):
        print("hv = {} eV,  E_F = {:.0f} eV,  Res = {:.0f} meV".format(
            entry.hv[scan_i],
            entry.efermi[scan_i],
            entry.efermi_fwhm[scan_i]*1000
        ))
        entry.plt_efermi_fit(scan_i=scan_i)

    hv = 90.0002326768388 eV,  E_F = 85 eV,  Res = 59 meV
    hv = 92.00027916234701 eV,  E_F = 87 eV,  Res = 57 meV
    hv = 93.99975364424496 eV,  E_F = 89 eV,  Res = 58 meV
    hv = 96.0002881448182 eV,  E_F = 91 eV,  Res = 58 meV
    hv = 98.00054946289589 eV,  E_F = 93 eV,  Res = 58 meV
    hv = 99.99983291751812 eV,  E_F = 95 eV,  Res = 59 meV
    hv = 102.00009245268568 eV,  E_F = 97 eV,  Res = 59 meV
    hv = 104.00003430155901 eV,  E_F = 99 eV,  Res = 59 meV
    hv = 106.00016412083477 eV,  E_F = 101 eV,  Res = 60 meV
    hv = 108.00036345505104 eV,  E_F = 103 eV,  Res = 58 meV

## Plot a single analyzer image at scan = 110 with the Fermi level aligned

    entry.isoscan(scan=110).show(yname='eef')

    <matplotlib.collections.QuadMesh object at 0x7809448c5090>

## Plotting iso-energetic cut at ekin = efermi

    entry.isoenergy(0).show()

    <matplotlib.collections.QuadMesh object at 0x780944943610>

## Plotting in the reciprocal space (k-space)

I have to define first the reference point to be used for the transformation. Meaning a point in the angular space which I know it correspond to a particular point in the k-space. In this case the graphene Dirac-point is for hv = 120 is at ekin = 114.3 eV and tht_p = -0.6 (see the figure below), which in the k-space has to correspond to kx = 1.7.

    hv_p = 120

    entry.isoscan(scan=hv_p, dscan=0).show(yname='ekin', cmap='cividis')

    tht_p = -0.6
    e_kin_p = 114.3
    plt.axvline(tht_p, color='w')
    plt.axhline(e_kin_p, color='w')

    entry.set_kspace(
        tht_p=tht_p,
        k_along_slit_p=1.7,
        scan_p=0,
        ks_p=0,
        e_kin_p=e_kin_p,
        inn_pot=14,
        p_hv=True,
        hv_p=hv_p,
    )

    tht_an = -18.040
    scan_type =  hv
    inn_pot = 14.000
    phi_an = 0.000
    k_perp_slit_for_kz = 0.000
    kspace transformation ready

Once it is set, all the isoscan or iscoenergy extracted from the entry will now get their proper k-space scales:

    entry.isoscan(120).show()

    <matplotlib.collections.QuadMesh object at 0x7809446c7890>

sphinx_gallery_thumbnail_number = 17

    entry.isoenergy(0).show(cmap='cividis')

    <matplotlib.collections.QuadMesh object at 0x7809445d9bd0>

I can also place together in a single figure different images:

    fig, axs = plt.subplots(1, 2)

    entry.isoscan(120).show(ax=axs[0])
    entry.isoenergy(-0.9).show(ax=axs[1])

    plt.tight_layout()

## Many other options:

    fig, axs = plt.subplots(2, 2)

    scan = 110
    dscan = 0
    ebin = -0.9
    debin = 0.01

    entry.isoscan(scan, dscan).show(ax=axs[0][0], xname='tht', yname='ekin')
    entry.isoscan(scan, dscan).show(ax=axs[0][1], cmap='binary')

    axs[0][1].axhline(ebin-debin)
    axs[0][1].axhline(ebin+debin)

    entry.isoenergy(ebin, debin).show(
        ax=axs[1][0], xname='tht', yname='phi', cmap='cividis')
    entry.isoenergy(ebin, debin).show(
        ax=axs[1][1], cmap='magma', cmapscale='log')

    axs[1][0].axhline(scan, color='w', ls='--')
    axs[0][1].axvline(1.7, color='r', ls='--')
    axs[1][1].axvline(1.7, color='r', ls='--')

    x_note = 0.05
    y_note = 0.98

    for ax in axs[0][:]:
        ax.annotate(
            "$scan \: = \: {} eV$".format(scan, dscan),
            (x_note, y_note),
            xycoords='axes fraction',
            size=8, rotation=0, ha="left", va="top",
            bbox=dict(
                boxstyle="round", fc='w', alpha=0.65, edgecolor='None', pad=0.05
            )
        )

    for ax in axs[1][:]:
        ax.annotate(
            "$E-E_F \: = \: {} \pm {} \; eV$".format(ebin, debin),
            (x_note, y_note),
            xycoords='axes fraction',
            size=8, rotation=0, ha="left", va="top",
            bbox=dict(
                boxstyle="round", fc='w', alpha=0.65, edgecolor='None', pad=0.05
            )
        )

    plt.tight_layout()

    /build/navarp-1RRLiy/navarp-1.6.0/examples/plot_gr_hv_scan.py:184: SyntaxWarning: "\:" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\:"? A raw string is also an option.
      "$scan \: = \: {} eV$".format(scan, dscan),
    /build/navarp-1RRLiy/navarp-1.6.0/examples/plot_gr_hv_scan.py:195: SyntaxWarning: "\:" is an invalid escape sequence. Such sequences will not work in the future. Did you mean "\\:"? A raw string is also an option.
      "$E-E_F \: = \: {} \pm {} \; eV$".format(ebin, debin),

Total running time of the script: (0 minutes 3.556 seconds)

Gallery generated by Sphinx-Gallery