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 97c5361..91e753d 100644 --- a/msspecbook/_build/html/Activity01/Activity01.html +++ b/msspecbook/_build/html/Activity01/Activity01.html @@ -189,7 +189,7 @@
As can be seen in Fig. 23, the peaks at 32° and 58.5° are well reproduced by the calculation for an Al polarity. Some discreapancies arise between the experimental work and this simulation especially for large polar angles. This may be due to a too small cluster in diameter for the deeper emitters.
- 1#!/usr/bin/env python
- 2# coding: utf8
- 3
- 4from ase.build import bulk
- 5import numpy as np
- 6from msspec.calculator import MSSPEC, XRaySource
- 7from msspec.utils import hemispherical_cluster, get_atom_index
- 8
- 9def create_clusters(nplanes=6):
- 10 def get_AlN_tags_planes(side, emitter):
- 11 AlN = bulk('AlN', crystalstructure='wurtzite', a=3.11, c=4.975)
- 12 [atom.set('tag', i) for i, atom in enumerate(AlN)]
- 13 if side == 'Al':
- 14 AlN.rotate([0,0,1],[0,0,-1])
- 15 Al_planes = range(0, nplanes, 2)
- 16 N_planes = range(1, nplanes, 2)
- 17 else:
- 18 N_planes = range(0, nplanes, 2)
- 19 Al_planes = range(1, nplanes, 2)
- 20 if emitter == 'Al':
- 21 tags = [0, 2]
- 22 planes = Al_planes
- 23 else:
- 24 tags = [1, 3]
- 25 planes = N_planes
- 26 return AlN, tags, planes
- 27
- 28 clusters = []
- 29 for side in ('Al', 'N'):
- 30 for emitter in ('Al', 'N'):
- 31 AlN, tags, planes = get_AlN_tags_planes(side, emitter)
- 32 for emitter_tag in tags:
- 33 for emitter_plane in planes:
- 34 cluster = hemispherical_cluster(AlN,
- 35 emitter_tag=emitter_tag,
- 36 emitter_plane=emitter_plane,
- 37 planes=emitter_plane+2)
- 38 cluster.absorber = get_atom_index(cluster, 0, 0, 0)
- 39 cluster.info.update({
- 40 'emitter_plane': emitter_plane,
- 41 'emitter_tag' : emitter_tag,
- 42 'emitter' : emitter,
- 43 'side' : side,
- 44 })
- 45 clusters.append(cluster)
- 46 print("Added cluster {}-side, emitter {}(tag {:d}) in "
- 47 "plane #{:d}".format(side, emitter, emitter_tag,
- 48 emitter_plane))
- 49 return clusters
- 50
- 51
- 52def compute(clusters, theta=np.arange(-20., 80., 1.), phi=0.):
- 53 data = None
- 54 for ic, cluster in enumerate(clusters):
- 55 # Retrieve info from cluster object
- 56 side = cluster.info['side']
- 57 emitter = cluster.info['emitter']
- 58 plane = cluster.info['emitter_plane']
- 59 tag = cluster.info['emitter_tag']
- 60
- 61 # Set the level and the kinetic energy
- 62 if emitter == 'Al':
- 63 level = '2p'
- 64 ke = 1407.
- 65 elif emitter == 'N':
- 66 level = '1s'
- 67 ke = 1083.
- 68
- 69 calc = MSSPEC(spectroscopy='PED', algorithm='expansion')
- 70
- 71 calc.source_parameters.energy = XRaySource.AL_KALPHA
- 72 calc.source_parameters.theta = -35
+ 1from ase.build import bulk
+ 2import numpy as np
+ 3from msspec.calculator import MSSPEC, XRaySource
+ 4from msspec.utils import hemispherical_cluster, get_atom_index
+ 5
+ 6def create_clusters(nplanes=6):
+ 7 def get_AlN_tags_planes(side, emitter):
+ 8 AlN = bulk('AlN', crystalstructure='wurtzite', a=3.11, c=4.975)
+ 9 [atom.set('tag', i) for i, atom in enumerate(AlN)]
+ 10 if side == 'Al':
+ 11 AlN.rotate([0,0,1],[0,0,-1])
+ 12 Al_planes = range(0, nplanes, 2)
+ 13 N_planes = range(1, nplanes, 2)
+ 14 else:
+ 15 N_planes = range(0, nplanes, 2)
+ 16 Al_planes = range(1, nplanes, 2)
+ 17 if emitter == 'Al':
+ 18 tags = [0, 2]
+ 19 planes = Al_planes
+ 20 else:
+ 21 tags = [1, 3]
+ 22 planes = N_planes
+ 23 return AlN, tags, planes
+ 24
+ 25 clusters = []
+ 26 for side in ('Al', 'N'):
+ 27 for emitter in ('Al', 'N'):
+ 28 AlN, tags, planes = get_AlN_tags_planes(side, emitter)
+ 29 for emitter_tag in tags:
+ 30 for emitter_plane in planes:
+ 31 cluster = hemispherical_cluster(AlN,
+ 32 emitter_tag=emitter_tag,
+ 33 emitter_plane=emitter_plane,
+ 34 planes=emitter_plane+2)
+ 35 cluster.absorber = get_atom_index(cluster, 0, 0, 0)
+ 36 cluster.info.update({
+ 37 'emitter_plane': emitter_plane,
+ 38 'emitter_tag' : emitter_tag,
+ 39 'emitter' : emitter,
+ 40 'side' : side,
+ 41 })
+ 42 clusters.append(cluster)
+ 43 print("Added cluster {}-side, emitter {}(tag {:d}) in "
+ 44 "plane #{:d}".format(side, emitter, emitter_tag,
+ 45 emitter_plane))
+ 46 return clusters
+ 47
+ 48
+ 49def compute(clusters, theta=np.arange(-20., 80., 1.), phi=0.):
+ 50 data = None
+ 51 for ic, cluster in enumerate(clusters):
+ 52 # Retrieve info from cluster object
+ 53 side = cluster.info['side']
+ 54 emitter = cluster.info['emitter']
+ 55 plane = cluster.info['emitter_plane']
+ 56 tag = cluster.info['emitter_tag']
+ 57
+ 58 # Set the level and the kinetic energy
+ 59 if emitter == 'Al':
+ 60 level = '2p'
+ 61 ke = 1407.
+ 62 elif emitter == 'N':
+ 63 level = '1s'
+ 64 ke = 1083.
+ 65
+ 66 calc = MSSPEC(spectroscopy='PED', algorithm='expansion')
+ 67
+ 68 calc.source_parameters.energy = XRaySource.AL_KALPHA
+ 69 calc.source_parameters.theta = -35
+ 70
+ 71 calc.detector_parameters.angular_acceptance = 4.
+ 72 calc.detector_parameters.average_sampling = 'medium'
73
- 74 calc.detector_parameters.angular_acceptance = 4.
- 75 calc.detector_parameters.average_sampling = 'medium'
- 76
- 77 calc.calculation_parameters.scattering_order = max(1, min(4, plane))
- 78 calc.calculation_parameters.path_filtering = 'forward_scattering'
- 79 calc.calculation_parameters.off_cone_events = 1
- 80 [a.set('forward_angle', 30.) for a in cluster]
- 81
- 82 calc.set_atoms(cluster)
- 83
- 84 data = calc.get_theta_scan(level=level, theta=theta, phi=phi,
- 85 kinetic_energy=ke, data=data)
- 86 dset = data[-1]
- 87 dset.title = "\'{}\' side - {}({}) tag #{:d}, plane #{:d}".format(
- 88 side, emitter, level, tag, plane)
+ 74 calc.calculation_parameters.scattering_order = max(1, min(4, plane))
+ 75 calc.calculation_parameters.path_filtering = 'forward_scattering'
+ 76 calc.calculation_parameters.off_cone_events = 1
+ 77 [a.set('forward_angle', 30.) for a in cluster]
+ 78
+ 79 calc.set_atoms(cluster)
+ 80
+ 81 data = calc.get_theta_scan(level=level, theta=theta, phi=phi,
+ 82 kinetic_energy=ke, data=data)
+ 83 dset = data[-1]
+ 84 dset.title = "\'{}\' side - {}({}) tag #{:d}, plane #{:d}".format(
+ 85 side, emitter, level, tag, plane)
+ 86
+ 87 return data
+ 88
89
- 90 return data
- 91
- 92
- 93def analysis(data):
- 94 tmp_data = {}
- 95 for dset in data:
- 96 info = dset.get_cluster().info
- 97 side = info['side']
- 98 emitter = info['emitter']
- 99 try:
-100 key = '{}_{}'.format(side, emitter)
-101 tmp_data[key] += dset.cross_section
-102 except KeyError:
-103 tmp_data[key] = dset.cross_section.copy()
-104
-105 tmp_data['theta'] = dset.theta.copy()
-106 tmp_data['Al_side'] = tmp_data['Al_Al'] / tmp_data['Al_N']
-107 tmp_data['N_side'] = tmp_data['N_Al'] / tmp_data['N_N']
-108
-109 # now add all columns
-110 substrate_dset = data.add_dset('Total substrate signal')
-111 substrate_dset.add_columns(**tmp_data)
-112
-113 view = substrate_dset.add_view('Ratios',
-114 title=r'Al(2p)/N(1s) ratios on both polar '
-115 r'sides of AlN in the (10$\bar{1}$0) '
-116 r'azimuthal plane',
-117 xlabel=r'$\Theta (\degree$)',
-118 ylabel='Intenisty ratio')
-119 view.select('theta', 'Al_side', legend='Al side',
-120 where="theta >= 0 and theta <=70")
-121 view.select('theta', 'N_side', legend='N side',
-122 where="theta >= 0 and theta <=70")
-123 view.set_plot_options(autoscale=True)
+ 90def analysis(data):
+ 91 tmp_data = {}
+ 92 for dset in data:
+ 93 info = dset.get_cluster().info
+ 94 side = info['side']
+ 95 emitter = info['emitter']
+ 96 try:
+ 97 key = '{}_{}'.format(side, emitter)
+ 98 tmp_data[key] += dset.cross_section
+ 99 except KeyError:
+100 tmp_data[key] = dset.cross_section.copy()
+101
+102 tmp_data['theta'] = dset.theta.copy()
+103 tmp_data['Al_side'] = tmp_data['Al_Al'] / tmp_data['Al_N']
+104 tmp_data['N_side'] = tmp_data['N_Al'] / tmp_data['N_N']
+105
+106 # now add all columns
+107 substrate_dset = data.add_dset('Total substrate signal')
+108 substrate_dset.add_columns(**tmp_data)
+109
+110 view = substrate_dset.add_view('Ratios',
+111 title=r'Al(2p)/N(1s) ratios on both polar '
+112 r'sides of AlN in the (10$\bar{1}$0) '
+113 r'azimuthal plane',
+114 xlabel=r'$\Theta (\degree$)',
+115 ylabel='Intenisty ratio')
+116 view.select('theta', 'Al_side', legend='Al side',
+117 where="theta >= 0 and theta <=70")
+118 view.select('theta', 'N_side', legend='N side',
+119 where="theta >= 0 and theta <=70")
+120 view.set_plot_options(autoscale=True)
+121
+122 return data
+123
124
-125 return data
-126
-127
-128clusters = create_clusters()
-129for cluster in clusters:
-130 cluster.edit()
-131exit()
-132data = compute(clusters)
-133data = analysis(data)
-134data.view()
-135
+125clusters = create_clusters()
+126for cluster in clusters:
+127 cluster.edit()
+128exit()
+129data = compute(clusters)
+130data = analysis(data)
+131data.view()
+132
In order to extract precise crystallographic information from electronic spectroscopy, we need to compare MsSpec calculations with experimental results and adjust the modelling parameters to simulate the experiment as accurately as possible.
+R-factors (reliability factors) are commonly used for this task. In the following example, we will see how MsSpec can extract the adsorption geometry of molecule.
+The carbon monoxide molecule can be adsorbed onto a Fe(001) surface in the hollow site. It was experimentally demonstrated that the CO molecule is tilted by 55\(\pm\)2° in <100> azimuthal directions. The molecule is bonded to the Fe surface by the carbon atom and the adsorption height was estimated to be \(\sim\) 0.6 Å.
+