diff --git a/msspecbook/Activity05/Activity05.ipynb b/msspecbook/Activity05/Activity05.ipynb index 486660a..ca3f110 100644 --- a/msspecbook/Activity05/Activity05.ipynb +++ b/msspecbook/Activity05/Activity05.ipynb @@ -11,6 +11,7 @@ "tags": [] }, "source": [ + "(forward-scattering)=\n", "# Activity 5: Multiple scattering in the forward scattering regime" ] }, @@ -877,7 +878,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.13" + "version": "3.11.3" } }, "nbformat": 4, diff --git a/msspecbook/Activity06/Activity06.ipynb b/msspecbook/Activity06/Activity06.ipynb index a95699d..f114ebd 100644 --- a/msspecbook/Activity06/Activity06.ipynb +++ b/msspecbook/Activity06/Activity06.ipynb @@ -133,7 +133,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.13" + "version": "3.11.3" } }, "nbformat": 4, diff --git a/msspecbook/Activity07/Activity07.ipynb b/msspecbook/Activity07/Activity07.ipynb index a0f1264..ee11a68 100644 --- a/msspecbook/Activity07/Activity07.ipynb +++ b/msspecbook/Activity07/Activity07.ipynb @@ -20,11 +20,112 @@ "tags": [] }, "source": [ + "So far you have seen that multiple scattering calculations with MsSpec can use two different algorithms: *matrix inversion* or *Rehr Albers series expansion*. When matrix inversion becomes impossible because the kinetic energy is too high and the number of atoms is too large, serial expansion is the alternative. This algorithm requires very little memory but it processes the scattering paths sequentially, which can lead to very long calculation times.\n", + "\n", + "In this activity, we will explore how to configure MsSpec to reduce this calculation time to compute the signal from a deep emitter in Si(001).\n", + "\n", + "\n", + "\n", + ":::" + ] + }, + { + "cell_type": "markdown", + "id": "2a2f7c01-3a7e-46d4-90aa-6ba2eada6337", + "metadata": {}, + "source": [ + "## The number of scattering paths\n", + "\n", + "To fix the idea, we will first evaluate how many scattering paths we need to compute for an emitter in the subsurface (2{sup}`nd` plane) or in the bulk (7{sup}`th` plane) of a Si(001) cluster." + ] + }, + { + "cell_type": "markdown", + "id": "0f78af28-335e-4f6b-9b98-929f9e6965f8", + "metadata": {}, + "source": [ + "::::{tab-set}\n", + "\n", + ":::{tab-item} Quiz\n", + "Create a cluster of Si(001) with the emitter in the subsurface, 40 Å diameter with 2 planes (since atoms below the emitter can be ignored at high kinetic energies).\n", + "\n", + "1. For an emitter in the subsurface, we can use single scattering (see {ref}`forward-scattering`). How many paths would be generated for this calculation ?\n", + "\n", + "2. Same question for an emitter in the 7{sup}`th` plane. If we were able to treat each scattering path within only 1 µs. How long would be such calculation ?\n", + "\n", + "```{note}\n", + "Remember that \n", + "1. for an emitter in plane $p$, the scattering order has to be at least the number of planes `above` the emitter\n", + "2. The number of scattering paths of order $n$ corresponds to the number of possibilities of arranging up to $n$ atoms (taking order into account).\n", + "```\n", + "\n", + "\n", + "::::" + ] + }, + { + "cell_type": "markdown", + "id": "a83ee1b8-dc25-4db9-a3bd-c5ba8443f758", + "metadata": {}, + "source": [ + ":::{toggle}\n", + "\n", + "To get the total number of paths generated by a cluster of $N$ atoms up to order $M$, use the following formula:\n", + "\n", + "```{math}\n", + ":label: eq-nbpaths\n", + "\\sum_{i=0}^{i=M} (N-1)^i\n", + "```\n", + "\n", + ":::{figure-md} nbpaths-fig\n", + "\"path\n", + "\n", + "The time for computing all scattering path for increasing cluster size and scattering order (up to 6{sup}`th` order with 739 atoms. (One path is assumed to be calculated within 1 µs)\n", + ":::\n", + "\n", + ":::" + ] + }, + { + "cell_type": "markdown", + "id": "5de975f5-8f3d-432e-bfcc-8455bc50a862", + "metadata": {}, + "source": [ + "## Paths filtering in MsSpec\n", + "\n", + "As you may expect, not all paths contribute significantly to the total intensity. This is why we can filter out some scattering paths and drastically reduce the computation time. MsSpec offers several filters for this. The 3 most common filters are:\n", + "1. the `forward_scattering` filter which allows all paths where each scattering angle is within a cone of defined aperture\n", + "2. the `backward_scattering` filter which is similar to the previous one but for backscattering direction\n", + "3. the `distance` filter which rejects all paths longer than a threshold distance\n", + "\n", + "The following figure illustrate the effect of theses filters on scattering paths\n", + "\n", ":::{figure-md} filters-fig\n", "\"path\n", "\n", - "Some examples of scattering paths with `forward_scattering`, `backward_scattering` and `distance` filters selected. The accepted forward angle is 45°, the accepted backscattering angle is 20° and the threshold distance is $6a_0$ where $a_0$ is the lattice parameter. Note that the yellow path is rejected but if the `off_cone_events` option is set to a value > 1, then it could have been accepted.\n", - ":::" + "Some examples of scattering paths with `forward_scattering`, `backward_scattering` and `distance` filters selected. The accepted forward angle is 45°, the accepted backscattering angle is 20° and the threshold distance is $6a_0$ where $a_0$ is the lattice parameter. Note that the yellow path is rejected but if the `off_cone_events` option is set to a value > 1, then it could have been accepted." + ] + }, + { + "cell_type": "markdown", + "id": "28aae2f7-2af9-4630-b89d-ab634725ad79", + "metadata": {}, + "source": [ + "## Application to a deep plane in a Si(001) sample\n", + "\n", + "The following script will compute contribution of all the planes of a Si(001) substrate to get the total photoelectron intensity of a Si(2s) polar scan. \n", + "\n", + "::::{tab-set}\n", + "\n", + ":::{tab-item} Quiz\n", + "\n", + "The script is almost completed, try to define path filtering options and compare results with and without filtering for emitter in plane n° 3 at scattering order 2.\n", + "\n", + "Compute the contribution of plane n° 7\n", + "\n", + ":::\n", + "\n", + "::::" ] } ], @@ -44,7 +145,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.13" + "version": "3.11.3" } }, "nbformat": 4, diff --git a/msspecbook/Activity07/Si001.py b/msspecbook/Activity07/Si001.py new file mode 100644 index 0000000..dce39d8 --- /dev/null +++ b/msspecbook/Activity07/Si001.py @@ -0,0 +1,165 @@ +# coding: utf8 + +import logging +import numpy as np +import os +import sys + +from ase.build import bulk, diamond111 + +from msspec.calculator import MSSPEC, XRaySource +from msspec.iodata import Data +from msspec.utils import hemispherical_cluster, get_atom_index, cut_sphere, cut_plane + +logging.basicConfig(level=logging.INFO) + +def create_clusters(nplanes=6, direction='100', a=5.43, c=5.43, radius=30): + clusters = [] + Si = bulk('Si', a=a, cubic=True) + + # Get scaled positions and cell + p = Si.get_scaled_positions() + cell = Si.get_cell() + + # Resize + covera = c / a + cell[2,:] *= covera + p[:,2] *= covera + Si.set_scaled_positions(p) + Si.set_cell(cell) + + if direction in ('001', '010', '100'): + pass + elif direction in ('111'): + Si.rotate([1,1,1], [1,1,0], rotate_cell=True) + Si.rotate([1,1,0], [1,0,0], rotate_cell=True) + Si.rotate([1,0,0], [0,0,1], rotate_cell=True) + + for iplane in range(nplanes): + #for iplane in (nplanes-1,): + logging.info(f'Building cluster #{iplane:d}/{nplanes-1:d}') + cluster = hemispherical_cluster(Si, #planes=max(iplane+1, 4), + diameter=70, + emitter_plane=iplane, + shape = 'cylindrical', + ) + + cluster = cut_sphere(cluster, radius = radius) + cluster = cut_plane(cluster, z = -a/4) + + for atom in cluster: + atom.set('mean_square_vibration', 0.006) + atom.set('mt_radius', 1.1) + cluster.absorber = get_atom_index(cluster, 0, 0, 0) + cluster.info.update(emitter_plane=iplane) + clusters.append(cluster) + return clusters + +def compute_polar_scan(cluster, data=None, phi=0, folder='calc', RA_cutoff=2, + max_ndif=6, level='2p', kinetic_energy=1382.28): + emitter_plane = cluster.info['emitter_plane'] + + calc = MSSPEC(spectroscopy='PED', algorithm='expansion', + folder=folder) + + calc.muffintin_parameters.interstitial_potential = 0. + + #calc.tmatrix_parameters.exchange_correlation = 'x_alpha_real' + calc.tmatrix_parameters.exchange_correlation = 'hedin_lundqvist_complex' + + calc.source_parameters.energy = XRaySource.AL_KALPHA + calc.source_parameters.theta = -54.7 + calc.source_parameters.phi = 90 + calc.spectroscopy_parameters.final_state = 1 + calc.detector_parameters.angular_acceptance = 1.0 + calc.detector_parameters.average_sampling = 'high' + + calc.calculation_parameters.scattering_order = min(max_ndif, + max(1, emitter_plane)) + #calc.tmatrix_parameters.lmax_mode ='imposed' + #calc.tmatrix_parameters.lmaxt = 10 + calc.tmatrix_parameters.tl_threshold = 1e-4 + #calc.calculation_parameters.scattering_order = 6 + #calc.calculation_parameters.mean_free_path = 10. + calc.calculation_parameters.vibrational_damping = 'averaged_tl' + calc.calculation_parameters.RA_cutoff = RA_cutoff + my_filters = ('forward_scattering', 'distance_cutoff') + calc.calculation_parameters.path_filtering = my_filters + #calc.calculation_parameters.path_filtering = 'forward_scattering' + calc.calculation_parameters.distance = 30 + calc.calculation_parameters.off_cone_events = 0 + calc.calculation_parameters.RA_cutoff_damping = 1 + [a.set('forward_angle', 40) for a in cluster] + + calc.phagen_parameters.noproto = '.false.' + + calc.set_atoms(cluster) + + data = calc.get_theta_scan(level=level, + theta=np.arange(-30., 80., 0.5), + kinetic_energy = kinetic_energy, + phi=phi, data=data) + + return data + +def sum_planes(data): + cs = None + ds = None + for dset in data: + theta = dset.theta + phi = dset.phi + try: + cs += dset.cross_section + ds += dset.direct_signal + except: + cs = dset.cross_section.copy() + ds = dset.direct_signal.copy() + + dset = data.add_dset('Substrate signal') + dset.add_columns(theta=theta, phi=phi, cross_section=cs, + direct_signal=ds, chi=(cs-ds)/ds) + + phi_values = np.unique(phi) + + view = dset.add_view('Substrate signal', + title=r'Si(2p)', + xlabel=r'$\Theta (\degree$)', + ylabel='Signal (a.u.)') + + for phi_value in phi_values: + condition = f'phi == {phi_value:.1f}' + legend = '$\Phi = $' + f'{phi_value:.1f}' + '$^\circ$' + view.select('theta', 'cross_section', where=condition, legend=legend) + view.set_plot_options(autoscale=True) + + +# Create the list of clusters +RA = 2 #int(sys.argv[1]) +NDIF = 5 #int(sys.argv[2]) +RAD = 20. #float(sys.argv[3]) +PHI = float(sys.argv[1]) +KE = float(sys.argv[2]) +#basename = f'RA{RA:d}_NDIF{NDIF:d}_RAD{RAD:.1f}_PHI{PHI:.1f}' +basename = f'PHI{PHI:.1f}_KE{KE:.2f}' +data = Data(basename) +clusters = create_clusters(nplanes=15, radius=RAD) + +if 'view' in sys.argv: + for cluster in clusters: + cluster.edit() + exit(0) + +for cluster in clusters: +#for cluster in (clusters[-1],): + data = compute_polar_scan(cluster, data, phi=PHI, + folder='calc_' + basename, + RA_cutoff=RA, + max_ndif=NDIF, + kinetic_energy=KE + ) + +sum_planes(data) +data.save('simulation_' + basename + '.hdf5', append=False) +data.export('simulation_' + basename) +#data.view() + diff --git a/msspecbook/Activity07/fig1.jpg b/msspecbook/Activity07/fig1.jpg new file mode 100644 index 0000000..fad7969 Binary files /dev/null and b/msspecbook/Activity07/fig1.jpg differ diff --git a/msspecbook/Activity07/nbpaths.py b/msspecbook/Activity07/nbpaths.py new file mode 100644 index 0000000..e90e9f4 --- /dev/null +++ b/msspecbook/Activity07/nbpaths.py @@ -0,0 +1,57 @@ +from ase.build import bulk +from msspec.utils import hemispherical_cluster, get_atom_index +from ase.visualize import view +from datetime import timedelta as td +import numpy as np +from matplotlib import pyplot as plt + +Si = bulk('Si', cubic=True) +planes = range(1,10) +natoms = [] +allt = [] +for emitter_plane in planes: + cluster = hemispherical_cluster(Si, diameter=40, emitter_plane=emitter_plane, planes=emitter_plane+1) + N = len(cluster) + npaths = np.sum([(N-1)**i for i in range(emitter_plane + 1)]) + t = npaths * 1e-6 + + natoms.append(len(cluster)) + allt.append(t) + + values=np.array([]) + conversion = [31557600, 86400, 3600, 60, 1, 1e-3, 1e-6] + units = np.array([" years", " days", "H", "M", "s", "ms", "µs"]) + for f in conversion: + values = np.append(values, t // f) + t -= values[-1] * f + + s = ' '.join(["{:.0f}{}".format(*_) for _ in zip(values[values>0][:3], units[values>0][:3])]) + print("Emitter in plane {:d}".format(emitter_plane)) + print("Number of atoms in the cluster: {:d}".format(len(cluster))) + print("{:d} scattering paths".format(npaths)) + print("{} to compute".format(s)) + print("*"*80) + + +colibri = 1/60 +one_day = 86400 +one_year = 365.25 * 86400 +roman_era = 1200 * one_year +jurassic_period = 55e6 * one_year +universe_age = 13.8e9 * one_year + +fig, ax = plt.subplots() + +for _ in [colibri, one_day, roman_era, jurassic_period, universe_age]: + ax.axhline(_, linestyle="--", color="black", lw=1) + +ax.semilogy(natoms, allt, color="red", lw=2) + +ax.scatter([natoms[0], natoms[6]], [allt[0],allt[6]], marker="o", color="red", lw=3) + + +plt.ylim(1e-6, 1e20) +plt.xlabel("Number of atoms for emitter in plane 1 to 9") +plt.ylabel("Computation time (s)") +plt.savefig('my_plot.png', transparent=True) +plt.show() \ No newline at end of file diff --git a/msspecbook/_build/.doctrees/Activity05/Activity05.doctree b/msspecbook/_build/.doctrees/Activity05/Activity05.doctree index 04ed461..cd5da2f 100644 Binary files a/msspecbook/_build/.doctrees/Activity05/Activity05.doctree and b/msspecbook/_build/.doctrees/Activity05/Activity05.doctree differ diff --git a/msspecbook/_build/.doctrees/Activity07/Activity07.doctree b/msspecbook/_build/.doctrees/Activity07/Activity07.doctree index 19e64b2..82cb32d 100644 Binary files a/msspecbook/_build/.doctrees/Activity07/Activity07.doctree and b/msspecbook/_build/.doctrees/Activity07/Activity07.doctree differ diff --git a/msspecbook/_build/.doctrees/environment.pickle b/msspecbook/_build/.doctrees/environment.pickle index bf0a36a..8e47235 100644 Binary files a/msspecbook/_build/.doctrees/environment.pickle and b/msspecbook/_build/.doctrees/environment.pickle differ diff --git a/msspecbook/_build/html/.buildinfo b/msspecbook/_build/html/.buildinfo index a78a743..556b4d6 100644 --- a/msspecbook/_build/html/.buildinfo +++ b/msspecbook/_build/html/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 0b896abf2c995b3493312dcbe0e8b47f +config: d64285b76259d47aa1d35d9bc7e7829a tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/msspecbook/_build/html/Activity01/Activity01.html b/msspecbook/_build/html/Activity01/Activity01.html index 1490ebd..97c5361 100644 --- a/msspecbook/_build/html/Activity01/Activity01.html +++ b/msspecbook/_build/html/Activity01/Activity01.html @@ -32,7 +32,7 @@ - + diff --git a/msspecbook/_build/html/Activity02/Activity02.html b/msspecbook/_build/html/Activity02/Activity02.html index bfe17c5..809683b 100644 --- a/msspecbook/_build/html/Activity02/Activity02.html +++ b/msspecbook/_build/html/Activity02/Activity02.html @@ -32,7 +32,7 @@ - + diff --git a/msspecbook/_build/html/Activity03/Activity03.html b/msspecbook/_build/html/Activity03/Activity03.html index 0526aac..8cb33b6 100644 --- a/msspecbook/_build/html/Activity03/Activity03.html +++ b/msspecbook/_build/html/Activity03/Activity03.html @@ -32,7 +32,7 @@ - + diff --git a/msspecbook/_build/html/Activity04/Activity04.html b/msspecbook/_build/html/Activity04/Activity04.html index 43f1673..78824fe 100644 --- a/msspecbook/_build/html/Activity04/Activity04.html +++ b/msspecbook/_build/html/Activity04/Activity04.html @@ -32,7 +32,7 @@ - + diff --git a/msspecbook/_build/html/Activity05/Activity05.html b/msspecbook/_build/html/Activity05/Activity05.html index 73760de..28cc2b8 100644 --- a/msspecbook/_build/html/Activity05/Activity05.html +++ b/msspecbook/_build/html/Activity05/Activity05.html @@ -32,7 +32,7 @@ - + @@ -359,7 +359,7 @@ document.write(`
-

Activity 5: Multiple scattering in the forward scattering regime#

+

Activity 5: Multiple scattering in the forward scattering regime#

In photoelectron diffraction, it is well known that for high photoelectron kinetic energy (typically > 900 eV), the scattering factor is strongly peaked in the forward direction. It means that photoelectrons are almost not deviated after a scattering event.

Peaks of intentisity are then usually observed for dense atomic directions of the sample. This is the forward scattering approximation.

For such high kinetic energy, multiple scattering is needed to accurately describe the measured intensity, but the matrix inversion algorithm cannot be used since the memory needed for storing the matrix itself would be generally too large. The matrix will contain @@ -516,7 +516,7 @@ document.write(` - + @@ -884,7 +884,7 @@ document.write(` - + @@ -892,7 +892,7 @@ document.write(` - + @@ -948,7 +948,7 @@ document.write(` - + @@ -956,7 +956,7 @@ document.write(` - + @@ -1004,7 +1004,7 @@ document.write(` - + diff --git a/msspecbook/_build/html/Activity06/Activity06.html b/msspecbook/_build/html/Activity06/Activity06.html index d3c0b34..7e2ae0f 100644 --- a/msspecbook/_build/html/Activity06/Activity06.html +++ b/msspecbook/_build/html/Activity06/Activity06.html @@ -32,7 +32,7 @@ - + diff --git a/msspecbook/_build/html/Activity07/Activity07.html b/msspecbook/_build/html/Activity07/Activity07.html index c8aca89..d0a5d0f 100644 --- a/msspecbook/_build/html/Activity07/Activity07.html +++ b/msspecbook/_build/html/Activity07/Activity07.html @@ -319,7 +319,9 @@ document.write(` `); - + @@ -335,6 +337,16 @@ document.write(`

@@ -346,13 +358,76 @@ document.write(`

Activity 7: Large clusters and path filtering#

+

So far you have seen that multiple scattering calculations with MsSpec can use two different algorithms: matrix inversion or Rehr Albers series expansion. When matrix inversion becomes impossible because the kinetic energy is too high and the number of atoms is too large, serial expansion is the alternative. This algorithm requires very little memory but it processes the scattering paths sequentially, which can lead to very long calculation times.

+

In this activity, we will explore how to configure MsSpec to reduce this calculation time to compute the signal from a deep emitter in Si(001).

+
+
+
+

The number of scattering paths#

+

To fix the idea, we will first evaluate how many scattering paths we need to compute for an emitter in the subsurface (2nd plane) or in the bulk (7th plane) of a Si(001) cluster.

+
+ +
+

Create a cluster of Si(001) with the emitter in the subsurface, 40 Å diameter with 2 planes (since atoms below the emitter can be ignored at high kinetic energies).

+
    +
  1. For an emitter in the subsurface, we can use single scattering (see Activity 5: Multiple scattering in the forward scattering regime). How many paths would be generated for this calculation ?

  2. +
  3. Same question for an emitter in the 7th plane. If we were able to treat each scattering path within only 1 µs. How long would be such calculation ?

  4. +
+
+

Note

+

Remember that

+
    +
  1. for an emitter in plane \(p\), the scattering order has to be at least the number of planes above the emitter

  2. +
  3. The number of scattering paths of order \(n\) corresponds to the number of possibilities of arranging up to \(n\) atoms (taking order into account).

  4. +
+
+
+
+
+

To get the total number of paths generated by a cluster of \(N\) atoms up to order \(M\), use the following formula:

+
+(3)#\[\sum_{i=0}^{i=M} (N-1)^i\]
+
+path filtering + +
+

Fig. 16 The time for computing all scattering path for increasing cluster size and scattering order (up to 6th order with 739 atoms. (One path is assumed to be calculated within 1 µs)#

+
+
+
+
+
+
+
+

Paths filtering in MsSpec#

+

As you may expect, not all paths contribute significantly to the total intensity. This is why we can filter out some scattering paths and drastically reduce the computation time. MsSpec offers several filters for this. The 3 most common filters are:

+
    +
  1. the forward_scattering filter which allows all paths where each scattering angle is within a cone of defined aperture

  2. +
  3. the backward_scattering filter which is similar to the previous one but for backscattering direction

  4. +
  5. the distance filter which rejects all paths longer than a threshold distance

  6. +
+

The following figure illustrate the effect of theses filters on scattering paths

path filtering
-

Fig. 16 Some examples of scattering paths with forward_scattering, backward_scattering and distance filters selected. The accepted forward angle is 45°, the accepted backscattering angle is 20° and the threshold distance is \(6a_0\) where \(a_0\) is the lattice parameter. Note that the yellow path is rejected but if the off_cone_events option is set to a value > 1, then it could have been accepted.#

+

Fig. 17 Some examples of scattering paths with forward_scattering, backward_scattering and distance filters selected. The accepted forward angle is 45°, the accepted backscattering angle is 20° and the threshold distance is \(6a_0\) where \(a_0\) is the lattice parameter. Note that the yellow path is rejected but if the off_cone_events option is set to a value > 1, then it could have been accepted.#

+
+
+

Application to a deep plane in a Si(001) sample#

+

The following script will compute contribution of all the planes of a Si(001) substrate to get the total photoelectron intensity of a Si(2s) polar scan.

+
+ +
+

The script is almost completed, try to define path filtering options and compare results with and without filtering for emitter in plane n° 3 at scattering order 2.

+

Compute the contribution of plane n° 7

+
+
+