Finish Activity 6
This commit is contained in:
parent
4404e636d9
commit
b30f209db9
|
@ -8,21 +8,22 @@
|
||||||
"# Activity 6: Effect of the temperature\n",
|
"# Activity 6: Effect of the temperature\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
"\n",
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"\n",
|
|
||||||
"## Surface and bulk effects of the temperature\n",
|
"## Surface and bulk effects of the temperature\n",
|
||||||
"\n",
|
"\n",
|
||||||
"In this example, we will look at the effects of the temperature on the X-Ray photoelectron diffraction from a copper substrate. We will base our python script on a paper published in 1986 by R. Trehan and S. Fadley. In their work, they performed azimutal scans of a copper(001) surface at 2 different polar angles: one at grazing incidence and one at 45° for incresing temperatures from 298K to roughly 1000K.\n",
|
"In this example, we will look at the effects of the temperature on the X-Ray photoelectron diffraction from a copper substrate. We will base our python script on a paper published in 1986 by R. Trehan and S. Fadley. In their work, they performed azimutal scans of a copper(001) surface at 2 different polar angles: one at grazing incidence and one at 45° for incresing temperatures from 298K to roughly 1000K.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"For each azimutal scan, they looked at the anisotropy of the signal, that is:\n",
|
"For each azimutal scan, they looked at the anisotropy of the signal, that is:\n",
|
||||||
"\n",
|
"\n",
|
||||||
"$\\frac{I_{max} - I_{min}}{I_{max}}=\\frac{\\Delta I}{I_{max}}$\n",
|
"```{math}\n",
|
||||||
|
":label: eq-anisotropy\n",
|
||||||
|
"\\frac{I_{max} - I_{min}}{I_{max}}=\\frac{\\Delta I}{I_{max}}\n",
|
||||||
|
"```\n",
|
||||||
"\n",
|
"\n",
|
||||||
"This value is representative of how clear are the *modulations* of the signal. As it was shown by their experiments, this anisotropy decreases when the temperature is increased due to the increased disorder in the structure coming from thermal agitation. They also showed that this variation in anisotropy is more pronounced for grazing incidence angles. This is related to the fact that surface atoms are expected to vibrate more than bulk ones. They also proposed single scattering calculations that reproduced well these results.\n",
|
"This value is representative of how clear are the *modulations* of the signal. They also proposed single scattering calculations that reproduced well these results.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"We will reproduce this kind of calculations to introduce the parameters that control the vibrational damping.\n",
|
"We will reproduce this kind of calculations to introduce the parameters that control the vibrational damping.\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
"(msd-paper)=\n",
|
||||||
":::{seealso}\n",
|
":::{seealso}\n",
|
||||||
"based on this paper from R. Trehan and C.S. Fadley\n",
|
"based on this paper from R. Trehan and C.S. Fadley\n",
|
||||||
"[Phys. Rev. B **34** p6784–98 (2012)](https://doi.org/10.1103/PhysRevB.34.6784)\n",
|
"[Phys. Rev. B **34** p6784–98 (2012)](https://doi.org/10.1103/PhysRevB.34.6784)\n",
|
||||||
|
@ -35,22 +36,50 @@
|
||||||
"The script contains 3 functions:\n",
|
"The script contains 3 functions:\n",
|
||||||
"1. The `create_clusters` function will build clusters with increasing number of planes, with the emitter being in the deepest plane for each cluster.\n",
|
"1. The `create_clusters` function will build clusters with increasing number of planes, with the emitter being in the deepest plane for each cluster.\n",
|
||||||
"2. The function `compute` will compute the azimuthal scan for a given cluster.\n",
|
"2. The function `compute` will compute the azimuthal scan for a given cluster.\n",
|
||||||
"3. The `analysis` function will sum the intensity from each plane for a given temperature. This will be the 'substrate total signal' (more on this in the following activity). The function will also compute the anisotropy"
|
"3. The `analysis` function will sum the intensity from each plane for a given temperature. This will be the *substrate total signal* (more on this in the {ref}`path-filtering` section). The function will also compute the anisotropy (equation {eq}`eq-anisotropy`).\n",
|
||||||
|
"\n",
|
||||||
|
"MsSpec can introduce temperature effects in two ways: either by using the Debye Waller model or by doing an average over the phase shifts. We will explore the latter in this example.\n",
|
||||||
|
"\n",
|
||||||
|
"Regardless of the option chosen to model temperature effects, we need to define mean square displacement (MSD) values of the atoms in our cluster. We will use the Debye model for this. The MSD is defined as follows:\n",
|
||||||
|
"\n",
|
||||||
|
":::{math}\n",
|
||||||
|
":label: eq-debye\n",
|
||||||
|
"<U_j^2(T)> = \\frac{3\\hbar^2 T}{M K_B \\Theta_D^2}\n",
|
||||||
|
":::\n",
|
||||||
|
"\n",
|
||||||
|
"where $\\hbar$ is the reduce Planck's constant, $T$ is the temperature, $M$ is the mass of the atom, $k_B$ is the Boltzmann's constant and $\\Theta_D$ is the Debye temperature of the sample.\n",
|
||||||
|
"\n",
|
||||||
|
"To get an idea of the typical order of magnitude for MSD, the figure below plots the values of MSD for copper for temperatures ranging from 300 K to 1000 K.\n",
|
||||||
|
"\n",
|
||||||
|
":::{figure-md} msd-fig\n",
|
||||||
|
"<img src=\"msd.jpg\" alt=\"Cu MSD\" width=\"600px\" align=\"center\">\n",
|
||||||
|
"\n",
|
||||||
|
"Variation of MSD for copper versus temperature using equation {eq}`eq-debye`\n",
|
||||||
|
":::"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"id": "69b8c17d-ab66-4092-a492-005f05d80495",
|
"id": "69b8c17d-ab66-4092-a492-005f05d80495",
|
||||||
"metadata": {},
|
"metadata": {
|
||||||
|
"editable": true,
|
||||||
|
"slideshow": {
|
||||||
|
"slide_type": ""
|
||||||
|
},
|
||||||
|
"tags": []
|
||||||
|
},
|
||||||
"source": [
|
"source": [
|
||||||
"::::{tab-set}\n",
|
"::::{tab-set}\n",
|
||||||
"\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",
|
||||||
"Complete the hilighted lines in the following script\n",
|
"With the help of the [MsSpec documentation](https://msspec.cnrs.fr/parameters.html) and the second paragraph p6791 of the [article cited above](#msd-paper),\n",
|
||||||
|
"complete the hilighted lines in the following script to compute the anisotropy of Cu(2p) $\\phi$-scans for polar angle $\\theta$=45° and 83°.\n",
|
||||||
|
"\n",
|
||||||
|
"How is varying the anisotropy versus the temperature. How can you qualitatively explain this variation ?\n",
|
||||||
"\n",
|
"\n",
|
||||||
"```{literalinclude} Cu_temperature.py\n",
|
"```{literalinclude} Cu_temperature.py\n",
|
||||||
":lineno-match:\n",
|
":lineno-match:\n",
|
||||||
":emphasize-lines:1,2\n",
|
":emphasize-lines: 40-41,44-48\n",
|
||||||
"```\n",
|
"```\n",
|
||||||
"\n",
|
"\n",
|
||||||
":::\n",
|
":::\n",
|
||||||
|
@ -59,12 +88,33 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"cell_type": "code",
|
"cell_type": "markdown",
|
||||||
"execution_count": null,
|
"id": "8dbafb54-cdb8-43fb-ba9e-ec1696e39731",
|
||||||
"id": "cfc8af7b-fec1-449c-9cf7-4d9e2ebe026a",
|
"metadata": {
|
||||||
"metadata": {},
|
"editable": true,
|
||||||
"outputs": [],
|
"slideshow": {
|
||||||
"source": []
|
"slide_type": ""
|
||||||
|
},
|
||||||
|
"tags": []
|
||||||
|
},
|
||||||
|
"source": [
|
||||||
|
"```{toggle}\n",
|
||||||
|
"\n",
|
||||||
|
":::{literalinclude} Cu_temperature_completed.py\n",
|
||||||
|
":lineno-match:\n",
|
||||||
|
":emphasize-lines: 40-41,44-48\n",
|
||||||
|
":::\n",
|
||||||
|
"\n",
|
||||||
|
":::{figure-md} anisotropy-fig\n",
|
||||||
|
"<img src=\"anisotropies.png\" alt=\"anisotropies\" width=\"600px\" align=\"center\">\n",
|
||||||
|
"\n",
|
||||||
|
"Variation of anisotropy as a function of temperature and polar angle for Cu(2p).\n",
|
||||||
|
":::\n",
|
||||||
|
"\n",
|
||||||
|
"The anisotropy decreases when the temperature is increased due to the increased disorder in the structure coming from thermal agitation. This variation in anisotropy is more pronounced for grazing incidence angles since surface atoms are expected to vibrate more than bulk ones and the expected mean depth of no-loss emission is $\\sim 1$ atomic layer at $\\theta = 83°$ and 3-4 layers at $\\theta = 45°$ as estimated by $\\Lambda_e\\sin\\theta$ (where $\\Lambda_e$ is the photoelectron mean free path at 560 eV).\n",
|
||||||
|
"\n",
|
||||||
|
"```"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"metadata": {
|
"metadata": {
|
||||||
|
@ -83,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,
|
||||||
|
|
|
@ -1,130 +1,126 @@
|
||||||
# coding: utf8
|
|
||||||
|
|
||||||
from ase.build import bulk
|
from ase.build import bulk
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
from msspec.calculator import MSSPEC, XRaySource
|
from msspec.calculator import MSSPEC, XRaySource
|
||||||
from msspec.utils import hemispherical_cluster, get_atom_index
|
from msspec.utils import hemispherical_cluster, get_atom_index
|
||||||
|
|
||||||
|
|
||||||
def create_clusters(nplanes=3):
|
def create_clusters(nplanes=3):
|
||||||
copper = bulk('Cu', a=3.6, cubic=True)
|
copper = bulk('Cu', a=3.6, cubic=True)
|
||||||
clusters = []
|
clusters = []
|
||||||
for emitter_plane in range(nplanes):
|
for emitter_plane in range(nplanes):
|
||||||
cluster = hemispherical_cluster(copper,
|
cluster = hemispherical_cluster(copper,
|
||||||
emitter_plane=emitter_plane,
|
emitter_plane=emitter_plane,
|
||||||
planes=emitter_plane+2,
|
planes=emitter_plane+1,
|
||||||
|
diameter=27,
|
||||||
shape='cylindrical')
|
shape='cylindrical')
|
||||||
cluster.absorber = get_atom_index(cluster, 0, 0, 0)
|
cluster.absorber = get_atom_index(cluster, 0, 0, 0)
|
||||||
|
# This is how to store extra information with your cluster
|
||||||
cluster.info.update({
|
cluster.info.update({
|
||||||
'emitter_plane': emitter_plane,
|
'emitter_plane': emitter_plane,
|
||||||
})
|
})
|
||||||
clusters.append(cluster)
|
clusters.append(cluster)
|
||||||
return clusters
|
return clusters
|
||||||
|
|
||||||
|
|
||||||
def compute(clusters, all_theta=[45., 83.],
|
def compute(clusters, all_theta=[45., 83.],
|
||||||
all_T=np.arange(300., 1000., 400.)):
|
all_T=np.arange(300., 1000., 400.)):
|
||||||
data = None
|
data = None
|
||||||
for ic, cluster in enumerate(clusters):
|
for cluster in clusters:
|
||||||
# Retrieve info from cluster object
|
# Retrieve emitter's plane from cluster object
|
||||||
plane = cluster.info['emitter_plane']
|
plane = cluster.info['emitter_plane']
|
||||||
|
|
||||||
calc = MSSPEC(spectroscopy='PED', algorithm='expansion')
|
calc = MSSPEC(spectroscopy='PED', algorithm='expansion')
|
||||||
calc.source_parameters.energy = XRaySource.AL_KALPHA
|
calc.source_parameters.energy = XRaySource.AL_KALPHA
|
||||||
calc.muffintin_parameters.interstitial_potential = 14.1
|
calc.muffintin_parameters.interstitial_potential = 14.1
|
||||||
|
|
||||||
|
# In simple scattering, it is common practice to use a real potential and
|
||||||
|
# manually define a mean free path arbitrarily lower than the actual physical
|
||||||
|
# value in an attempt to reproduce multiple scattering effects.
|
||||||
|
calc.tmatrix_parameters.exchange_correlation = 'x_alpha_real'
|
||||||
|
calc.calculation_parameters.mean_free_path = ... # -> half of the mean free
|
||||||
|
# path (see p6785)
|
||||||
|
# Parameters for temperature effects
|
||||||
calc.calculation_parameters.vibrational_damping = 'averaged_tl'
|
calc.calculation_parameters.vibrational_damping = 'averaged_tl'
|
||||||
calc.calculation_parameters.use_debye_model = True
|
calc.calculation_parameters.use_debye_model = ..... # Use the MsSpec help
|
||||||
calc.calculation_parameters.debye_temperature = 343
|
calc.calculation_parameters.debye_temperature = ... # and p6791 of the paper
|
||||||
calc.calculation_parameters.vibration_scaling = 1.2
|
calc.calculation_parameters.vibration_scaling = ... # -> How much more do
|
||||||
|
# surface atoms vibrate
|
||||||
calc.detector_parameters.average_sampling = 'high'
|
# than bulk atoms?
|
||||||
|
calc.detector_parameters.average_sampling = 'low'
|
||||||
calc.detector_parameters.angular_acceptance = 5.7
|
calc.detector_parameters.angular_acceptance = 5.7
|
||||||
|
|
||||||
for atom in cluster:
|
calc.calculation_parameters.scattering_order = 1
|
||||||
atom.set('forward_angle', 30)
|
|
||||||
atom.set('backward_angle', 30)
|
|
||||||
filters = ['forward_scattering', 'backward_scattering']
|
|
||||||
calc.calculation_parameters.path_filtering = filters
|
|
||||||
|
|
||||||
calc.calculation_parameters.RA_cutoff = 2
|
|
||||||
|
|
||||||
for T in all_T:
|
for T in all_T:
|
||||||
for theta in all_theta:
|
# Define the sample temperature
|
||||||
calc.calculation_parameters.temperature = T
|
calc.calculation_parameters.temperature = T
|
||||||
calc.calculation_parameters.scattering_order = min(1 + plane, 3)
|
# Set the atoms and compute an azimuthal scan
|
||||||
#calc.calculation_parameters.scattering_order = min(1 + plane, 3)
|
calc.set_atoms(cluster)
|
||||||
calc.set_atoms(cluster)
|
data = calc.get_phi_scan(level='2p', theta=all_theta,
|
||||||
data = calc.get_phi_scan(level='2p3/2', theta=theta,
|
phi=np.linspace(0, 100, 51),
|
||||||
phi=np.linspace(0, 100),
|
kinetic_energy=560, data=data)
|
||||||
kinetic_energy=560, data=data)
|
# Small changes to add some details in both the title of the dataset
|
||||||
dset = data[-1]
|
# and the figure
|
||||||
dset.title = "plane #{:d}, T={:f}K, theta={:f}°".format(plane,
|
view = data[-1].views[-1]
|
||||||
T,
|
t = view._plotopts['title'] + f" (plane #{plane:d}, T={T:.0f} K)"
|
||||||
theta)
|
data[-1].title = t
|
||||||
|
view.set_plot_options(autoscale=True, title=t)
|
||||||
dset.add_parameter(group='misc', name='plane', value=plane, unit='')
|
calc.shutdown()
|
||||||
dset.add_parameter(group='misc', name='T', value=T, unit='')
|
|
||||||
dset.add_parameter(group='misc', name='theta', value=theta, unit='')
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
def analysis(data):
|
def analysis(data, all_theta, all_T, nplanes):
|
||||||
all_plane = []
|
# Sum cross_section for all emitter's plane at a given T
|
||||||
all_T = []
|
# Compute the anisotropy
|
||||||
all_theta = []
|
results = dict.fromkeys(all_T, [])
|
||||||
|
anisotropy = []
|
||||||
for dset in data:
|
for dset in data:
|
||||||
plane = dset.get_parameter('misc', 'plane')['value']
|
# Retrieve temperature
|
||||||
T = dset.get_parameter('misc', 'T')['value']
|
T = float(dset.get_parameter('CalculationParameters', 'temperature')['value'])
|
||||||
theta = dset.get_parameter('misc', 'theta')['value']
|
# Update the sum in results
|
||||||
cs = dset.cross_section.copy()
|
if len(results[T]) == 0:
|
||||||
phi = dset.phi.copy()
|
results[T] = dset.cross_section
|
||||||
|
else:
|
||||||
|
results[T] += dset.cross_section
|
||||||
|
|
||||||
if plane not in all_plane: all_plane.append(plane)
|
anisotropy_dset = data.add_dset("Anisotropies")
|
||||||
if T not in all_T: all_T.append(T)
|
anisotropy_dset.add_columns(temperature=all_T)
|
||||||
if theta not in all_theta: all_theta.append(theta)
|
for theta in all_theta:
|
||||||
|
col_name = f"theta{theta:.0f}"
|
||||||
|
col_values = []
|
||||||
|
i = np.where(dset.theta == theta)[0]
|
||||||
|
for T in all_T:
|
||||||
|
cs = results[T][i]
|
||||||
|
Imax = np.max(cs)
|
||||||
|
Imin = np.min(cs)
|
||||||
|
A = (Imax - Imin)/Imax
|
||||||
|
col_values.append(A)
|
||||||
|
anisotropy_dset.add_columns(**{col_name:col_values/np.max(col_values)})
|
||||||
|
|
||||||
def get_anisotropy(theta, T):
|
|
||||||
cs = None
|
|
||||||
for dset in data:
|
|
||||||
try:
|
|
||||||
_T = dset.get_parameter('misc', 'T')['value']
|
|
||||||
_theta = dset.get_parameter('misc', 'theta')['value']
|
|
||||||
_cs = dset.cross_section.copy()
|
|
||||||
phi = dset.phi.copy()
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
if _theta == theta and _T == T:
|
|
||||||
try:
|
|
||||||
cs += _cs
|
|
||||||
except:
|
|
||||||
cs = _cs
|
|
||||||
Imax = np.max(cs)
|
|
||||||
Imin = np.min(cs)
|
|
||||||
return (Imax - Imin)/Imax
|
|
||||||
|
|
||||||
# create a substrate dataset for each T and theta
|
|
||||||
anisotropy_dset = data.add_dset("all")
|
|
||||||
anisotropy_view = anisotropy_dset.add_view('Anisotropies',
|
anisotropy_view = anisotropy_dset.add_view('Anisotropies',
|
||||||
title='Relative anisotropies for Cu(2p)',
|
title='Relative anisotropies for Cu(2p)',
|
||||||
marker='o',
|
marker='o',
|
||||||
xlabel='T (K)',
|
xlabel='T (K)',
|
||||||
ylabel=r'$\frac{\Delta I / I_{max}(T)}{\Delta I_{300}'
|
ylabel=r'$\frac{\Delta I / I_{max}(T)}{\Delta I_{300}'
|
||||||
r'/ I_{max}(300)} (\%)$')
|
r'/ I_{max}(300)} (\%)$',
|
||||||
|
autoscale=True)
|
||||||
for theta in all_theta:
|
for theta in all_theta:
|
||||||
for T in all_T:
|
col_name = f"theta{theta:.0f}"
|
||||||
A = get_anisotropy(theta, T)
|
anisotropy_view.select('temperature', col_name,
|
||||||
A0 = get_anisotropy(theta, np.min(all_T))
|
legend=r'$\theta = {:.0f} \degree$'.format(theta))
|
||||||
|
|
||||||
anisotropy_dset.add_row(temperature=T, theta=theta, anisotropy=A/A0)
|
|
||||||
|
|
||||||
anisotropy_view.select('temperature', 'anisotropy',
|
|
||||||
where='theta == {:f}'.format(theta),
|
|
||||||
legend=r'$\theta = {:.0f} \degree$'.format(theta))
|
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
clusters = create_clusters()
|
|
||||||
data = compute(clusters)
|
if __name__ == "__main__":
|
||||||
data = analysis(data)
|
nplanes = 4
|
||||||
data.view()
|
all_theta = np.array([45, 83])
|
||||||
|
all_theta = np.array([300., 1000.])
|
||||||
|
|
||||||
|
clusters = create_clusters(nplanes=nplanes)
|
||||||
|
data = compute(clusters, all_T=all_T, all_theta=all_theta)
|
||||||
|
data = analysis(data, all_T=all_T, all_theta=all_theta, nplanes=nplanes)
|
||||||
|
data.view()
|
||||||
|
|
|
@ -0,0 +1,126 @@
|
||||||
|
from ase.build import bulk
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from msspec.calculator import MSSPEC, XRaySource
|
||||||
|
from msspec.utils import hemispherical_cluster, get_atom_index
|
||||||
|
|
||||||
|
def create_clusters(nplanes=3):
|
||||||
|
copper = bulk('Cu', a=3.6, cubic=True)
|
||||||
|
clusters = []
|
||||||
|
for emitter_plane in range(nplanes):
|
||||||
|
cluster = hemispherical_cluster(copper,
|
||||||
|
emitter_plane=emitter_plane,
|
||||||
|
planes=emitter_plane+1,
|
||||||
|
diameter=27,
|
||||||
|
shape='cylindrical')
|
||||||
|
cluster.absorber = get_atom_index(cluster, 0, 0, 0)
|
||||||
|
# This is how to store extra information with your cluster
|
||||||
|
cluster.info.update({
|
||||||
|
'emitter_plane': emitter_plane,
|
||||||
|
})
|
||||||
|
clusters.append(cluster)
|
||||||
|
return clusters
|
||||||
|
|
||||||
|
|
||||||
|
def compute(clusters, all_theta=[45., 83.],
|
||||||
|
all_T=np.arange(300., 1000., 400.)):
|
||||||
|
data = None
|
||||||
|
for cluster in clusters:
|
||||||
|
# Retrieve emitter's plane from cluster object
|
||||||
|
plane = cluster.info['emitter_plane']
|
||||||
|
|
||||||
|
calc = MSSPEC(spectroscopy='PED', algorithm='expansion')
|
||||||
|
calc.source_parameters.energy = XRaySource.AL_KALPHA
|
||||||
|
calc.muffintin_parameters.interstitial_potential = 14.1
|
||||||
|
|
||||||
|
# In simple scattering, it is common practice to use a real potential and
|
||||||
|
# manually define a mean free path arbitrarily lower than the actual physical
|
||||||
|
# value in an attempt to reproduce multiple scattering effects.
|
||||||
|
calc.tmatrix_parameters.exchange_correlation = 'x_alpha_real'
|
||||||
|
calc.calculation_parameters.mean_free_path = .5 * 9.1
|
||||||
|
|
||||||
|
# Parameters for temperature effects
|
||||||
|
calc.calculation_parameters.vibrational_damping = 'averaged_tl'
|
||||||
|
calc.calculation_parameters.use_debye_model = True
|
||||||
|
calc.calculation_parameters.debye_temperature = 343
|
||||||
|
calc.calculation_parameters.vibration_scaling = 2.3
|
||||||
|
|
||||||
|
|
||||||
|
calc.detector_parameters.average_sampling = 'low'
|
||||||
|
calc.detector_parameters.angular_acceptance = 5.7
|
||||||
|
|
||||||
|
calc.calculation_parameters.scattering_order = 1
|
||||||
|
|
||||||
|
|
||||||
|
for T in all_T:
|
||||||
|
# Define the sample temperature
|
||||||
|
calc.calculation_parameters.temperature = T
|
||||||
|
# Set the atoms and compute an azimuthal scan
|
||||||
|
calc.set_atoms(cluster)
|
||||||
|
data = calc.get_phi_scan(level='2p', theta=all_theta,
|
||||||
|
phi=np.linspace(0, 100, 51),
|
||||||
|
kinetic_energy=560, data=data)
|
||||||
|
# Small changes to add some details in both the title of the dataset
|
||||||
|
# and the figure
|
||||||
|
view = data[-1].views[-1]
|
||||||
|
t = view._plotopts['title'] + f" (plane #{plane:d}, T={T:.0f} K)"
|
||||||
|
data[-1].title = t
|
||||||
|
view.set_plot_options(autoscale=True, title=t)
|
||||||
|
calc.shutdown()
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def analysis(data, all_theta, all_T, nplanes):
|
||||||
|
# Sum cross_section for all emitter's plane at a given T
|
||||||
|
# Compute the anisotropy
|
||||||
|
results = dict.fromkeys(all_T, [])
|
||||||
|
anisotropy = []
|
||||||
|
for dset in data:
|
||||||
|
# Retrieve temperature
|
||||||
|
T = float(dset.get_parameter('CalculationParameters', 'temperature')['value'])
|
||||||
|
# Update the sum in results
|
||||||
|
if len(results[T]) == 0:
|
||||||
|
results[T] = dset.cross_section
|
||||||
|
else:
|
||||||
|
results[T] += dset.cross_section
|
||||||
|
|
||||||
|
anisotropy_dset = data.add_dset("Anisotropies")
|
||||||
|
anisotropy_dset.add_columns(temperature=all_T)
|
||||||
|
for theta in all_theta:
|
||||||
|
col_name = f"theta{theta:.0f}"
|
||||||
|
col_values = []
|
||||||
|
i = np.where(dset.theta == theta)[0]
|
||||||
|
for T in all_T:
|
||||||
|
cs = results[T][i]
|
||||||
|
Imax = np.max(cs)
|
||||||
|
Imin = np.min(cs)
|
||||||
|
A = (Imax - Imin)/Imax
|
||||||
|
col_values.append(A)
|
||||||
|
anisotropy_dset.add_columns(**{col_name:col_values/np.max(col_values)})
|
||||||
|
|
||||||
|
|
||||||
|
anisotropy_view = anisotropy_dset.add_view('Anisotropies',
|
||||||
|
title='Relative anisotropies for Cu(2p)',
|
||||||
|
marker='o',
|
||||||
|
xlabel='T (K)',
|
||||||
|
ylabel=r'$\frac{\Delta I / I_{max}(T)}{\Delta I_{300}'
|
||||||
|
r'/ I_{max}(300)} (\%)$',
|
||||||
|
autoscale=True)
|
||||||
|
for theta in all_theta:
|
||||||
|
col_name = f"theta{theta:.0f}"
|
||||||
|
anisotropy_view.select('temperature', col_name,
|
||||||
|
legend=r'$\theta = {:.0f} \degree$'.format(theta))
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
nplanes = 4
|
||||||
|
all_theta = np.array([45, 83])
|
||||||
|
all_theta = np.array([300., 1000.])
|
||||||
|
|
||||||
|
clusters = create_clusters(nplanes=nplanes)
|
||||||
|
data = compute(clusters, all_T=all_T, all_theta=all_theta)
|
||||||
|
data = analysis(data, all_T=all_T, all_theta=all_theta, nplanes=nplanes)
|
||||||
|
data.view()
|
Binary file not shown.
Binary file not shown.
After Width: | Height: | Size: 60 KiB |
Binary file not shown.
After Width: | Height: | Size: 27 KiB |
Loading…
Reference in New Issue