Completed Activity 7
This commit is contained in:
		
							parent
							
								
									fed5ccd667
								
							
						
					
					
						commit
						f704dae1ba
					
				|  | @ -878,7 +878,7 @@ | ||||||
|    "name": "python", |    "name": "python", | ||||||
|    "nbconvert_exporter": "python", |    "nbconvert_exporter": "python", | ||||||
|    "pygments_lexer": "ipython3", |    "pygments_lexer": "ipython3", | ||||||
|    "version": "3.11.3" |    "version": "3.11.13" | ||||||
|   } |   } | ||||||
|  }, |  }, | ||||||
|  "nbformat": 4, |  "nbformat": 4, | ||||||
|  |  | ||||||
|  | @ -133,7 +133,7 @@ | ||||||
|    "name": "python", |    "name": "python", | ||||||
|    "nbconvert_exporter": "python", |    "nbconvert_exporter": "python", | ||||||
|    "pygments_lexer": "ipython3", |    "pygments_lexer": "ipython3", | ||||||
|    "version": "3.11.3" |    "version": "3.11.13" | ||||||
|   } |   } | ||||||
|  }, |  }, | ||||||
|  "nbformat": 4, |  "nbformat": 4, | ||||||
|  |  | ||||||
|  | @ -103,7 +103,8 @@ | ||||||
|     ":::{figure-md} filters-fig\n", |     ":::{figure-md} filters-fig\n", | ||||||
|     "<img src=\"filters.jpg\" alt=\"path filtering\" width=\"600px\" align=\"center\">\n", |     "<img src=\"filters.jpg\" alt=\"path filtering\" width=\"600px\" align=\"center\">\n", | ||||||
|     "\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." |     "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", | ||||||
|  |     ":::" | ||||||
|    ] |    ] | ||||||
|   }, |   }, | ||||||
|   { |   { | ||||||
|  | @ -113,7 +114,9 @@ | ||||||
|    "source": [ |    "source": [ | ||||||
|     "## Application to a deep plane in a Si(001) sample\n", |     "## Application to a deep plane in a Si(001) sample\n", | ||||||
|     "\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", |     "The following script will compute the contribution of a Si(2p) atom in the 4{sup}`th` plane of a Si(001) cluster at scattering order 3.\n", | ||||||
|  |     "\n", | ||||||
|  |     "Taking into account all scattering paths took 15 minutes to compute.\n", | ||||||
|     "\n", |     "\n", | ||||||
|     "(msd-paper)=\n", |     "(msd-paper)=\n", | ||||||
|     ":::{seealso}\n", |     ":::{seealso}\n", | ||||||
|  | @ -126,14 +129,46 @@ | ||||||
|     "\n", |     "\n", | ||||||
|     ":::{tab-item} <i class=\"fa-solid fa-circle-question\"></i> Quiz\n", |     ":::{tab-item} <i class=\"fa-solid fa-circle-question\"></i> Quiz\n", | ||||||
|     "\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", |     "The following script is almost completed, try to define path filtering options (no backscattering, accept all paths with forward angles < 40° and reject paths longer than the diameter of the cluster).\n", | ||||||
|     "\n", |     "\n", | ||||||
|     "Compute the contribution of plane n° 7\n", |     "```{literalinclude} Si001.py\n", | ||||||
|  |     ":lineno-match:\n", | ||||||
|  |     ":emphasize-lines: 37-41\n", | ||||||
|  |     "```\n", | ||||||
|  |     "\n", | ||||||
|  |     "1. How long was your calculation ?\n", | ||||||
|  |     "2. How does it compare to the calculation with **all** scattering paths up to order 3 ?\n", | ||||||
|  |     "3. What is the proportion of scattering paths of order 3 that were actually taken into account ?\n", | ||||||
|     "\n", |     "\n", | ||||||
|     ":::\n", |     ":::\n", | ||||||
|     "\n", |     "\n", | ||||||
|     "::::" |     "::::" | ||||||
|    ] |    ] | ||||||
|  |   }, | ||||||
|  |   { | ||||||
|  |    "cell_type": "markdown", | ||||||
|  |    "id": "19fbd486-b0c1-450c-a00d-79984945aefd", | ||||||
|  |    "metadata": {}, | ||||||
|  |    "source": [ | ||||||
|  |     "```{toggle}\n", | ||||||
|  |     "The calculation took few seconds and the result is very close to the calculation with all scattering paths.\n", | ||||||
|  |     "\n", | ||||||
|  |     "Only 0.01% of 3{sup}`rd` order paths were actually taken into account\n", | ||||||
|  |     "\n", | ||||||
|  |     ":::{figure-md} si-fig\n", | ||||||
|  |     "<img src=\"results.png\" alt=\"Si polar scan\" width=\"600px\" align=\"center\">\n", | ||||||
|  |     "\n", | ||||||
|  |     "Si(2p) polar scan (contribution of an emitter in the 4{sup}`th` plane with all 7 114 945 scattering paths taken into account (orange curve), and for only 1525 filtered paths (blue curve).\n", | ||||||
|  |     "\n", | ||||||
|  |     ":::\n", | ||||||
|  |     "\n", | ||||||
|  |     ":::{literalinclude} Si001_completed.py\n", | ||||||
|  |     ":lineno-match:\n", | ||||||
|  |     ":emphasize-lines: 37-41\n", | ||||||
|  |     ":::\n", | ||||||
|  |     "\n", | ||||||
|  |     "``` " | ||||||
|  |    ] | ||||||
|   } |   } | ||||||
|  ], |  ], | ||||||
|  "metadata": { |  "metadata": { | ||||||
|  | @ -152,7 +187,7 @@ | ||||||
|    "name": "python", |    "name": "python", | ||||||
|    "nbconvert_exporter": "python", |    "nbconvert_exporter": "python", | ||||||
|    "pygments_lexer": "ipython3", |    "pygments_lexer": "ipython3", | ||||||
|    "version": "3.11.3" |    "version": "3.11.13" | ||||||
|   } |   } | ||||||
|  }, |  }, | ||||||
|  "nbformat": 4, |  "nbformat": 4, | ||||||
|  |  | ||||||
|  | @ -1,165 +1,56 @@ | ||||||
| # coding: utf8 | # coding: utf8 | ||||||
| 
 | 
 | ||||||
| import logging |  | ||||||
| import numpy as np | import numpy as np | ||||||
| import os | from ase.build import bulk | ||||||
| import sys |  | ||||||
| 
 |  | ||||||
| from ase.build import bulk, diamond111 |  | ||||||
| 
 | 
 | ||||||
| from msspec.calculator import MSSPEC, XRaySource | from msspec.calculator import MSSPEC, XRaySource | ||||||
| from msspec.iodata import Data | from msspec.iodata import Data | ||||||
| from msspec.utils import hemispherical_cluster, get_atom_index, cut_sphere, cut_plane | from msspec.utils import hemispherical_cluster, get_atom_index | ||||||
| 
 |  | ||||||
| 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 | # Create the cluster | ||||||
| RA   = 2   #int(sys.argv[1]) | a = 5.43 | ||||||
| NDIF = 5   #int(sys.argv[2]) | Si = bulk('Si', a=a, cubic=True) | ||||||
| RAD  = 20. #float(sys.argv[3]) | cluster = hemispherical_cluster(Si, | ||||||
| PHI  = float(sys.argv[1]) |                                 diameter=30, planes=4, | ||||||
| KE   = float(sys.argv[2]) |                                 emitter_plane=3, | ||||||
| #basename = f'RA{RA:d}_NDIF{NDIF:d}_RAD{RAD:.1f}_PHI{PHI:.1f}' |                                 shape = 'cylindrical', | ||||||
| basename = f'PHI{PHI:.1f}_KE{KE:.2f}' |                                 ) | ||||||
| data = Data(basename) | for atom in cluster: | ||||||
| clusters = create_clusters(nplanes=15, radius=RAD) |     atom.set('mean_square_vibration', 0.006) | ||||||
|  |     atom.set('mt_radius', 1.1) | ||||||
|  | cluster.emitter = get_atom_index(cluster, 0, 0, 0) | ||||||
| 
 | 
 | ||||||
| if 'view' in sys.argv: | # Create a calculator and set parameters | ||||||
|     for cluster in clusters: | calc = MSSPEC(spectroscopy='PED', algorithm='expansion') | ||||||
|         cluster.edit() |  | ||||||
|     exit(0) |  | ||||||
| 
 | 
 | ||||||
| for cluster in clusters: | calc.source_parameters.energy = XRaySource.AL_KALPHA | ||||||
| #for cluster in (clusters[-1],): | calc.source_parameters.theta  = -54.7 | ||||||
|     data = compute_polar_scan(cluster, data, phi=PHI, | calc.source_parameters.phi    = 90 | ||||||
|                               folder='calc_' + basename, | calc.spectroscopy_parameters.final_state = 1 | ||||||
|                               RA_cutoff=RA, |  | ||||||
|                               max_ndif=NDIF, |  | ||||||
|                               kinetic_energy=KE |  | ||||||
|                               ) |  | ||||||
| 
 | 
 | ||||||
| sum_planes(data) | calc.calculation_parameters.scattering_order = 3 | ||||||
| data.save('simulation_' + basename + '.hdf5', append=False) | calc.tmatrix_parameters.tl_threshold = 1e-4 | ||||||
| data.export('simulation_' + basename) | calc.calculation_parameters.vibrational_damping = 'averaged_tl' | ||||||
| #data.view() | calc.calculation_parameters.RA_cutoff = 2 | ||||||
|  |   | ||||||
|  | # Define path filtering options such that you only | ||||||
|  | # accept scattering paths with a forward cone <= 40° | ||||||
|  | # and whose length are <= cluster diameter | ||||||
|  | # | ||||||
|  | # | ||||||
| 
 | 
 | ||||||
|  | calc.set_atoms(cluster) | ||||||
|  | 
 | ||||||
|  | # Compute and add previous data for comparison | ||||||
|  | data = calc.get_theta_scan(level='2p', | ||||||
|  |                             theta=np.arange(-30., 80., 0.5), | ||||||
|  |                             phi=0, | ||||||
|  |                             kinetic_energy=1382.28) | ||||||
|  | no_filters = Data.load('path_filtering.hdf5') | ||||||
|  | data[0].add_columns(**{'no_filters': no_filters[0].cross_section}) | ||||||
|  | view = data[0].views[0] | ||||||
|  | view.select('theta', 'cross_section', index=0, legend="With path filtering") | ||||||
|  | view.select('theta', 'no_filters', legend="Without path filtering") | ||||||
|  | 
 | ||||||
|  | data.view() | ||||||
|  |  | ||||||
|  | @ -0,0 +1,56 @@ | ||||||
|  | # coding: utf8 | ||||||
|  | 
 | ||||||
|  | import numpy as np | ||||||
|  | from ase.build import bulk | ||||||
|  | 
 | ||||||
|  | from msspec.calculator import MSSPEC, XRaySource | ||||||
|  | from msspec.iodata import Data | ||||||
|  | from msspec.utils import hemispherical_cluster, get_atom_index | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # Create the cluster | ||||||
|  | a = 5.43 | ||||||
|  | Si = bulk('Si', a=a, cubic=True) | ||||||
|  | cluster = hemispherical_cluster(Si, | ||||||
|  |                                 diameter=30, planes=4, | ||||||
|  |                                 emitter_plane=3, | ||||||
|  |                                 shape = 'cylindrical', | ||||||
|  |                                 ) | ||||||
|  | for atom in cluster: | ||||||
|  |     atom.set('mean_square_vibration', 0.006) | ||||||
|  |     atom.set('mt_radius', 1.1) | ||||||
|  | cluster.emitter = get_atom_index(cluster, 0, 0, 0) | ||||||
|  | 
 | ||||||
|  | # Create a calculator and set parameters | ||||||
|  | calc = MSSPEC(spectroscopy='PED', algorithm='expansion') | ||||||
|  | 
 | ||||||
|  | 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.calculation_parameters.scattering_order = 3 | ||||||
|  | calc.tmatrix_parameters.tl_threshold = 1e-4 | ||||||
|  | calc.calculation_parameters.vibrational_damping = 'averaged_tl' | ||||||
|  | calc.calculation_parameters.RA_cutoff = 2 | ||||||
|  | 
 | ||||||
|  | my_filters = ('forward_scattering', 'distance_cutoff') | ||||||
|  | calc.calculation_parameters.path_filtering = my_filters | ||||||
|  | calc.calculation_parameters.distance = 30 | ||||||
|  | calc.calculation_parameters.off_cone_events = 0 | ||||||
|  | [a.set('forward_angle', 40) for a in cluster] | ||||||
|  | 
 | ||||||
|  | calc.set_atoms(cluster) | ||||||
|  | 
 | ||||||
|  | # Compute and add previous data for comparison | ||||||
|  | data = calc.get_theta_scan(level='2p', | ||||||
|  |                             theta=np.arange(-30., 80., 0.5), | ||||||
|  |                             phi=0, | ||||||
|  |                             kinetic_energy=1382.28) | ||||||
|  | no_filters = Data.load('path_filtering.hdf5') | ||||||
|  | data[0].add_columns(**{'no_filters': no_filters[0].cross_section}) | ||||||
|  | view = data[0].views[0] | ||||||
|  | view.select('theta', 'cross_section', index=0, legend="With path filtering") | ||||||
|  | view.select('theta', 'no_filters', legend="Without path filtering") | ||||||
|  | 
 | ||||||
|  | data.view() | ||||||
|  | @ -11,6 +11,7 @@ natoms = [] | ||||||
| allt = [] | allt = [] | ||||||
| for emitter_plane in planes: | for emitter_plane in planes: | ||||||
|     cluster = hemispherical_cluster(Si, diameter=40, emitter_plane=emitter_plane, planes=emitter_plane+1) |     cluster = hemispherical_cluster(Si, diameter=40, emitter_plane=emitter_plane, planes=emitter_plane+1) | ||||||
|  |     cluster.edit() | ||||||
|     N = len(cluster) |     N = len(cluster) | ||||||
|     npaths = np.sum([(N-1)**i for i in range(emitter_plane + 1)]) |     npaths = np.sum([(N-1)**i for i in range(emitter_plane + 1)]) | ||||||
|     t = npaths * 1e-6 |     t = npaths * 1e-6 | ||||||
|  | @ -54,4 +55,4 @@ plt.ylim(1e-6, 1e20) | ||||||
| plt.xlabel("Number of atoms for emitter in plane 1 to 9") | plt.xlabel("Number of atoms for emitter in plane 1 to 9") | ||||||
| plt.ylabel("Computation time (s)") | plt.ylabel("Computation time (s)") | ||||||
| plt.savefig('my_plot.png', transparent=True) | plt.savefig('my_plot.png', transparent=True) | ||||||
| plt.show() | plt.show() | ||||||
|  |  | ||||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 84 KiB | 
		Loading…
	
		Reference in New Issue