Completed Activity 7
This commit is contained in:
		
							parent
							
								
									fed5ccd667
								
							
						
					
					
						commit
						f704dae1ba
					
				|  | @ -878,7 +878,7 @@ | |||
|    "name": "python", | ||||
|    "nbconvert_exporter": "python", | ||||
|    "pygments_lexer": "ipython3", | ||||
|    "version": "3.11.3" | ||||
|    "version": "3.11.13" | ||||
|   } | ||||
|  }, | ||||
|  "nbformat": 4, | ||||
|  |  | |||
|  | @ -133,7 +133,7 @@ | |||
|    "name": "python", | ||||
|    "nbconvert_exporter": "python", | ||||
|    "pygments_lexer": "ipython3", | ||||
|    "version": "3.11.3" | ||||
|    "version": "3.11.13" | ||||
|   } | ||||
|  }, | ||||
|  "nbformat": 4, | ||||
|  |  | |||
|  | @ -103,7 +103,8 @@ | |||
|     ":::{figure-md} filters-fig\n", | ||||
|     "<img src=\"filters.jpg\" alt=\"path filtering\" width=\"600px\" align=\"center\">\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": [ | ||||
|     "## 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", | ||||
|     "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", | ||||
|     "(msd-paper)=\n", | ||||
|     ":::{seealso}\n", | ||||
|  | @ -126,14 +129,46 @@ | |||
|     "\n", | ||||
|     ":::{tab-item} <i class=\"fa-solid fa-circle-question\"></i> 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", | ||||
|     "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", | ||||
|     "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", | ||||
|     "::::" | ||||
|    ] | ||||
|   }, | ||||
|   { | ||||
|    "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": { | ||||
|  | @ -152,7 +187,7 @@ | |||
|    "name": "python", | ||||
|    "nbconvert_exporter": "python", | ||||
|    "pygments_lexer": "ipython3", | ||||
|    "version": "3.11.3" | ||||
|    "version": "3.11.13" | ||||
|   } | ||||
|  }, | ||||
|  "nbformat": 4, | ||||
|  |  | |||
|  | @ -1,165 +1,56 @@ | |||
| # coding: utf8 | ||||
| 
 | ||||
| import logging | ||||
| import numpy as np | ||||
| import os | ||||
| import sys | ||||
| 
 | ||||
| from ase.build import bulk, diamond111 | ||||
| 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, 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) | ||||
| from msspec.utils import hemispherical_cluster, get_atom_index | ||||
| 
 | ||||
| 
 | ||||
| # 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) | ||||
| # 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) | ||||
| 
 | ||||
| if 'view' in sys.argv: | ||||
|     for cluster in clusters: | ||||
|         cluster.edit() | ||||
|     exit(0) | ||||
| # Create a calculator and set parameters | ||||
| calc = MSSPEC(spectroscopy='PED', algorithm='expansion') | ||||
| 
 | ||||
| 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 | ||||
|                               ) | ||||
| calc.source_parameters.energy = XRaySource.AL_KALPHA | ||||
| calc.source_parameters.theta  = -54.7 | ||||
| calc.source_parameters.phi    = 90 | ||||
| calc.spectroscopy_parameters.final_state = 1 | ||||
| 
 | ||||
| sum_planes(data) | ||||
| data.save('simulation_' + basename + '.hdf5', append=False) | ||||
| data.export('simulation_' + basename) | ||||
| #data.view() | ||||
| 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 | ||||
|   | ||||
| # 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 = [] | ||||
| for emitter_plane in planes: | ||||
|     cluster = hemispherical_cluster(Si, diameter=40, emitter_plane=emitter_plane, planes=emitter_plane+1) | ||||
|     cluster.edit() | ||||
|     N = len(cluster) | ||||
|     npaths = np.sum([(N-1)**i for i in range(emitter_plane + 1)]) | ||||
|     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.ylabel("Computation time (s)") | ||||
| 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