xarpes 0.1.0__py3-none-any.whl → 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- xarpes/.ipynb_checkpoints/__init__-checkpoint.py +13 -0
- xarpes/.ipynb_checkpoints/band_map-checkpoint.py +205 -0
- xarpes/.ipynb_checkpoints/distributions-checkpoint.py +430 -0
- xarpes/.ipynb_checkpoints/functions-checkpoint.py +133 -0
- xarpes/.ipynb_checkpoints/plotting-checkpoint.py +157 -0
- xarpes/__init__.py +1 -1
- xarpes/band_map.py +48 -11
- xarpes/distributions.py +366 -40
- xarpes/functions.py +102 -7
- xarpes/plotting.py +30 -18
- xarpes-0.2.1.dist-info/LICENSE +674 -0
- {xarpes-0.1.0.dist-info → xarpes-0.2.1.dist-info}/METADATA +8 -1
- xarpes-0.2.1.dist-info/RECORD +14 -0
- xarpes-0.1.0.dist-info/LICENSE +0 -339
- xarpes-0.1.0.dist-info/RECORD +0 -9
- {xarpes-0.1.0.dist-info → xarpes-0.2.1.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
__version__ = '0.1.0'
|
|
2
|
+
|
|
3
|
+
from . import plotting
|
|
4
|
+
|
|
5
|
+
from .band_map import *
|
|
6
|
+
from .distributions import *
|
|
7
|
+
from .functions import *
|
|
8
|
+
from .plotting import *
|
|
9
|
+
|
|
10
|
+
# from . import plotting
|
|
11
|
+
# from xarpes.plotting import *
|
|
12
|
+
# from xarpes.distributions import *
|
|
13
|
+
# from xarpes.distributions import fermi_dirac
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
# Copyright (C) 2024 xARPES Developers
|
|
2
|
+
# This program is free software under the terms of the GNU GPLv3 license.
|
|
3
|
+
|
|
4
|
+
# get_ax_fig_plt and add_fig_kwargs originate from pymatgen/util/plotting.py.
|
|
5
|
+
# Copyright (C) 2011-2024 Shyue Ping Ong and the pymatgen Development Team
|
|
6
|
+
# Pymatgen is released under the MIT License.
|
|
7
|
+
|
|
8
|
+
# See also abipy/tools/plotting.py.
|
|
9
|
+
# Copyright (C) 2021 Matteo Giantomassi and the AbiPy Group
|
|
10
|
+
# AbiPy is free software under the terms of the GNU GPLv2 license.
|
|
11
|
+
|
|
12
|
+
"""The band map class and allowed operations on it."""
|
|
13
|
+
|
|
14
|
+
import numpy as np
|
|
15
|
+
from .plotting import get_ax_fig_plt, add_fig_kwargs
|
|
16
|
+
from .distributions import fermi_dirac
|
|
17
|
+
|
|
18
|
+
class band_map():
|
|
19
|
+
r"""Class for the band map from the ARPES experiment.
|
|
20
|
+
|
|
21
|
+
Parameters
|
|
22
|
+
----------
|
|
23
|
+
intensities : ndarray
|
|
24
|
+
2D array of counts for given (E,k) or (E,angle) pairs [counts]
|
|
25
|
+
angles : ndarray
|
|
26
|
+
1D array of angular values for the abscissa [degrees]
|
|
27
|
+
ekin : ndarray
|
|
28
|
+
1D array of kinetic energy values for the ordinate [eV]
|
|
29
|
+
energy_resolution : float
|
|
30
|
+
Energy resolution of the detector [eV]
|
|
31
|
+
temperature : float, None
|
|
32
|
+
Temperature of the sample [K]
|
|
33
|
+
hnuminphi : float, None
|
|
34
|
+
Kinetic energy minus the work function [eV]
|
|
35
|
+
hnuminphi_std : float, None
|
|
36
|
+
Standard deviation of kinetic energy minus work function [eV]
|
|
37
|
+
"""
|
|
38
|
+
def __init__(self, intensities, angles, ekin, energy_resolution=None,
|
|
39
|
+
temperature=None, hnuminphi=None, hnuminphi_std=None):
|
|
40
|
+
self.intensities = intensities
|
|
41
|
+
self.angles = angles
|
|
42
|
+
self.ekin = ekin
|
|
43
|
+
self.energy_resolution = energy_resolution
|
|
44
|
+
self.temperature = temperature
|
|
45
|
+
self.hnuminphi = hnuminphi
|
|
46
|
+
self.hnuminphi_std = hnuminphi_std
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def hnuminphi(self):
|
|
50
|
+
r"""Returns the photon energy minus the work function in eV if it has
|
|
51
|
+
been set, either during instantiation, with the setter, or by fitting
|
|
52
|
+
the Fermi-Dirac distribution to the integrated weight.
|
|
53
|
+
|
|
54
|
+
Returns
|
|
55
|
+
-------
|
|
56
|
+
hnuminphi : float, None
|
|
57
|
+
Kinetic energy minus the work function [eV]
|
|
58
|
+
"""
|
|
59
|
+
return self._hnuminphi
|
|
60
|
+
|
|
61
|
+
@hnuminphi.setter
|
|
62
|
+
def hnuminphi(self, hnuminphi):
|
|
63
|
+
r"""Manually sets the photon energy minus the work function in eV if it
|
|
64
|
+
has been set; otherwise returns None.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
hnuminphi : float, None
|
|
69
|
+
Kinetic energy minus the work function [eV]
|
|
70
|
+
"""
|
|
71
|
+
self._hnuminphi = hnuminphi
|
|
72
|
+
|
|
73
|
+
@property
|
|
74
|
+
def hnuminphi_std(self):
|
|
75
|
+
r"""Returns standard deviation of the photon energy minus the work
|
|
76
|
+
function in eV.
|
|
77
|
+
|
|
78
|
+
Returns
|
|
79
|
+
-------
|
|
80
|
+
hnuminphi_std : float
|
|
81
|
+
Standard deviation of energy minus the work function [eV]
|
|
82
|
+
"""
|
|
83
|
+
return self._hnuminphi_std
|
|
84
|
+
|
|
85
|
+
@hnuminphi_std.setter
|
|
86
|
+
def hnuminphi_std(self, hnuminphi_std):
|
|
87
|
+
r"""Manually sets the standard deviation of photon energy minus the
|
|
88
|
+
work function in eV.
|
|
89
|
+
|
|
90
|
+
Parameters
|
|
91
|
+
----------
|
|
92
|
+
hnuminphi_std : float
|
|
93
|
+
Standard deviation of energy minus the work function [eV]
|
|
94
|
+
"""
|
|
95
|
+
self._hnuminphi_std = hnuminphi_std
|
|
96
|
+
|
|
97
|
+
def shift_angles(self, shift):
|
|
98
|
+
r"""
|
|
99
|
+
Shifts the angles by the specified amount in degrees. Used to shift
|
|
100
|
+
from the detector angle to the material angle.
|
|
101
|
+
|
|
102
|
+
Parameters
|
|
103
|
+
----------
|
|
104
|
+
shift : float
|
|
105
|
+
Angular shift [degrees]
|
|
106
|
+
"""
|
|
107
|
+
self.angles = self.angles + shift
|
|
108
|
+
|
|
109
|
+
@add_fig_kwargs
|
|
110
|
+
def fit_fermi_edge(self, hnuminphi_guess, background_guess=0.0,
|
|
111
|
+
integrated_weight_guess=1.0, angle_min=-np.infty,
|
|
112
|
+
angle_max=np.infty, ekin_min=-np.infty,
|
|
113
|
+
ekin_max=np.infty, ax=None, **kwargs):
|
|
114
|
+
r"""
|
|
115
|
+
Fits the Fermi edge of the band map and plots the result.
|
|
116
|
+
Also sets hnuminphi, the kinetic energy minus the work function in eV.
|
|
117
|
+
The fitting includes an energy convolution with an abscissa range
|
|
118
|
+
expanded by 5 times the energy resolution standard deviation.
|
|
119
|
+
|
|
120
|
+
Parameters
|
|
121
|
+
----------
|
|
122
|
+
hnuminphi_guess : float
|
|
123
|
+
Initial guess for kinetic energy minus the work function [eV]
|
|
124
|
+
background_guess : float
|
|
125
|
+
Initial guess for background intensity [counts]
|
|
126
|
+
integrated_weight_guess : float
|
|
127
|
+
Initial guess for integrated spectral intensity [counts]
|
|
128
|
+
angle_min : float
|
|
129
|
+
Minimum angle of integration interval [degrees]
|
|
130
|
+
angle_max : float
|
|
131
|
+
Maximum angle of integration interval [degrees]
|
|
132
|
+
ekin_min : float
|
|
133
|
+
Minimum kinetic energy of integration interval [eV]
|
|
134
|
+
ekin_max : float
|
|
135
|
+
Maximum kinetic energy of integration interval [eV]
|
|
136
|
+
ax : Matplotlib-Axes / NoneType
|
|
137
|
+
Axis for plotting the Fermi edge on. Created if not provided by
|
|
138
|
+
the user.
|
|
139
|
+
|
|
140
|
+
Other parameters
|
|
141
|
+
----------------
|
|
142
|
+
**kwargs : dict, optional
|
|
143
|
+
Additional arguments passed on to add_fig_kwargs. See the keyword
|
|
144
|
+
table below.
|
|
145
|
+
|
|
146
|
+
Returns
|
|
147
|
+
-------
|
|
148
|
+
fig : Matplotlib-Figure
|
|
149
|
+
Figure containing the Fermi edge fit
|
|
150
|
+
"""
|
|
151
|
+
from xarpes.functions import fit_leastsq
|
|
152
|
+
|
|
153
|
+
ax, fig, plt = get_ax_fig_plt(ax=ax)
|
|
154
|
+
|
|
155
|
+
min_angle_index = np.argmin(np.abs(self.angles - angle_min))
|
|
156
|
+
max_angle_index = np.argmin(np.abs(self.angles - angle_max))
|
|
157
|
+
|
|
158
|
+
min_ekin_index = np.argmin(np.abs(self.ekin - ekin_min))
|
|
159
|
+
max_ekin_index = np.argmin(np.abs(self.ekin - ekin_max))
|
|
160
|
+
|
|
161
|
+
energy_range = self.ekin[min_ekin_index:max_ekin_index]
|
|
162
|
+
|
|
163
|
+
integrated_intensity = np.trapz(
|
|
164
|
+
self.intensities[min_ekin_index:max_ekin_index,
|
|
165
|
+
min_angle_index:max_angle_index], axis=1)
|
|
166
|
+
|
|
167
|
+
fdir_initial = fermi_dirac(temperature=self.temperature,
|
|
168
|
+
hnuminphi=hnuminphi_guess,
|
|
169
|
+
background=background_guess,
|
|
170
|
+
integrated_weight=integrated_weight_guess,
|
|
171
|
+
name='Initial guess')
|
|
172
|
+
|
|
173
|
+
parameters = np.array(
|
|
174
|
+
[hnuminphi_guess, background_guess, integrated_weight_guess])
|
|
175
|
+
|
|
176
|
+
extra_args = (self.energy_resolution)
|
|
177
|
+
|
|
178
|
+
popt, pcov = fit_leastsq(parameters, energy_range, integrated_intensity,
|
|
179
|
+
fdir_initial, extra_args)
|
|
180
|
+
|
|
181
|
+
fdir_final = fermi_dirac(temperature=self.temperature,
|
|
182
|
+
hnuminphi=popt[0], background=popt[1],
|
|
183
|
+
integrated_weight=popt[2],
|
|
184
|
+
name='Fitted result')
|
|
185
|
+
|
|
186
|
+
self.hnuminphi = popt[0]
|
|
187
|
+
self.hnuminphi_std = np.sqrt(np.diag(pcov))[0][0]
|
|
188
|
+
|
|
189
|
+
ax.set_xlabel(r'$E_{\mathrm{kin}}$ (-)')
|
|
190
|
+
ax.set_ylabel('Counts (-)')
|
|
191
|
+
ax.set_xlim([ekin_min, ekin_max])
|
|
192
|
+
|
|
193
|
+
ax.plot(energy_range, integrated_intensity, label='Data')
|
|
194
|
+
|
|
195
|
+
ax.plot(energy_range, fdir_initial.convolve(energy_range,
|
|
196
|
+
energy_resolution=self.energy_resolution),
|
|
197
|
+
label=fdir_initial.name)
|
|
198
|
+
|
|
199
|
+
ax.plot(energy_range, fdir_final.convolve(energy_range,
|
|
200
|
+
energy_resolution=self.energy_resolution),
|
|
201
|
+
label=fdir_final.name)
|
|
202
|
+
|
|
203
|
+
ax.legend()
|
|
204
|
+
|
|
205
|
+
return fig
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
# Copyright (C) 2024 xARPES Developers
|
|
2
|
+
# This program is free software under the terms of the GNU GPLv3 license.
|
|
3
|
+
|
|
4
|
+
"""The distributions used throughout the code."""
|
|
5
|
+
|
|
6
|
+
class distribution:
|
|
7
|
+
r"""Parent class for distributions. The class cannot be used on its own,
|
|
8
|
+
but is used to instantiate unique and non-unique distributions.
|
|
9
|
+
|
|
10
|
+
Parameters
|
|
11
|
+
----------
|
|
12
|
+
name : str
|
|
13
|
+
Non-unique name for instances, not to be modified after instantiation.
|
|
14
|
+
"""
|
|
15
|
+
def __init__(self, name):
|
|
16
|
+
self._name = name
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def name(self):
|
|
20
|
+
r"""Returns the name of the class instance.
|
|
21
|
+
|
|
22
|
+
Returns
|
|
23
|
+
-------
|
|
24
|
+
name : str
|
|
25
|
+
Non-unique name for instances, not to be modified after
|
|
26
|
+
instantiation.
|
|
27
|
+
"""
|
|
28
|
+
return self._name
|
|
29
|
+
|
|
30
|
+
class unique_distribution(distribution):
|
|
31
|
+
r"""Parent class for unique distributions, to be used one at a time, e.g.,
|
|
32
|
+
during the background of an MDC fit or the Fermi-Dirac distribution.
|
|
33
|
+
|
|
34
|
+
Parameters
|
|
35
|
+
----------
|
|
36
|
+
label : str
|
|
37
|
+
Unique label for instances, identical to the name for unique
|
|
38
|
+
distributions. Not to be modified after instantiation.
|
|
39
|
+
"""
|
|
40
|
+
def __init__(self, name):
|
|
41
|
+
super().__init__(name)
|
|
42
|
+
self._label = name
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def label(self):
|
|
46
|
+
r"""Returns the unique class label.
|
|
47
|
+
|
|
48
|
+
Returns
|
|
49
|
+
-------
|
|
50
|
+
label : str
|
|
51
|
+
Unique label for instances, identical to the name for unique
|
|
52
|
+
distributions. Not to be modified after instantiation.
|
|
53
|
+
"""
|
|
54
|
+
return self._label
|
|
55
|
+
|
|
56
|
+
class constant(unique_distribution):
|
|
57
|
+
r"""Child class for constant distributions, used e.g., during MDC fitting.
|
|
58
|
+
The constant class is unique, only one instance should be used per task.
|
|
59
|
+
|
|
60
|
+
Parameters
|
|
61
|
+
----------
|
|
62
|
+
offset : float
|
|
63
|
+
The value of the distribution for the abscissa equal to 0.
|
|
64
|
+
"""
|
|
65
|
+
def __init__(self, offset):
|
|
66
|
+
super().__init__(name='constant')
|
|
67
|
+
self._offset = offset
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def offset(self):
|
|
71
|
+
r"""Returns the offset of the constant distribution.
|
|
72
|
+
|
|
73
|
+
Returns
|
|
74
|
+
-------
|
|
75
|
+
offset : float
|
|
76
|
+
The value of the distribution for the abscissa equal to 0.
|
|
77
|
+
"""
|
|
78
|
+
return self._offset
|
|
79
|
+
|
|
80
|
+
@offset.setter
|
|
81
|
+
def set_offset(self, x):
|
|
82
|
+
r"""Sets the offset of the constant distribution.
|
|
83
|
+
|
|
84
|
+
Parameters
|
|
85
|
+
----------
|
|
86
|
+
offset : float
|
|
87
|
+
The value of the distribution for the abscissa equal to 0.
|
|
88
|
+
"""
|
|
89
|
+
self._offset = x
|
|
90
|
+
|
|
91
|
+
class linear(unique_distribution):
|
|
92
|
+
r"""Child cass for for linear distributions, used e.g., during MDC fitting.
|
|
93
|
+
The constant class is unique, only one instance should be used per task.
|
|
94
|
+
|
|
95
|
+
Parameters
|
|
96
|
+
----------
|
|
97
|
+
offset : float
|
|
98
|
+
The value of the distribution for the abscissa equal to 0.
|
|
99
|
+
slope : float
|
|
100
|
+
The linear slope of the distribution w.r.t. the abscissa.
|
|
101
|
+
"""
|
|
102
|
+
def __init__(self, slope, offset):
|
|
103
|
+
super().__init__(name='linear')
|
|
104
|
+
self._offset = offset
|
|
105
|
+
self._slope = slope
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def offset(self):
|
|
109
|
+
r"""Returns the offset of the linear distribution.
|
|
110
|
+
|
|
111
|
+
Returns
|
|
112
|
+
-------
|
|
113
|
+
offset : float
|
|
114
|
+
The value of the distribution for the abscissa equal to 0.
|
|
115
|
+
"""
|
|
116
|
+
return self._offset
|
|
117
|
+
|
|
118
|
+
@offset.setter
|
|
119
|
+
def set_offset(self, x):
|
|
120
|
+
r"""Sets the offset of the linear distribution.
|
|
121
|
+
|
|
122
|
+
Parameters
|
|
123
|
+
----------
|
|
124
|
+
offset : float
|
|
125
|
+
The value of the distribution for the abscissa equal to 0.
|
|
126
|
+
"""
|
|
127
|
+
self._offset = x
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def slope(self):
|
|
131
|
+
r"""Returns the slope of the linear distribution.
|
|
132
|
+
|
|
133
|
+
Returns
|
|
134
|
+
-------
|
|
135
|
+
slope : float
|
|
136
|
+
The linear slope of the distribution w.r.t. the abscissa.
|
|
137
|
+
"""
|
|
138
|
+
return self._slope
|
|
139
|
+
|
|
140
|
+
@slope.setter
|
|
141
|
+
def set_slope(self, x):
|
|
142
|
+
r"""Sets the slope of the linear distribution.
|
|
143
|
+
|
|
144
|
+
Parameters
|
|
145
|
+
----------
|
|
146
|
+
slope : float
|
|
147
|
+
The linear slope of the distribution w.r.t. the abscissa.
|
|
148
|
+
"""
|
|
149
|
+
self._slope = x
|
|
150
|
+
|
|
151
|
+
class linear(unique_distribution):
|
|
152
|
+
r"""Child cass for for linear distributions, used e.g., during MDC fitting.
|
|
153
|
+
The constant class is unique, only one instance should be used per task.
|
|
154
|
+
|
|
155
|
+
Parameters
|
|
156
|
+
----------
|
|
157
|
+
offset : float
|
|
158
|
+
The value of the distribution for the abscissa equal to 0.
|
|
159
|
+
slope : float
|
|
160
|
+
The linear slope of the distribution w.r.t. the abscissa.
|
|
161
|
+
"""
|
|
162
|
+
def __init__(self, slope, offset):
|
|
163
|
+
|
|
164
|
+
super().__init__(name='linear')
|
|
165
|
+
self._offset = offset
|
|
166
|
+
self._slope = slope
|
|
167
|
+
|
|
168
|
+
@property
|
|
169
|
+
def offset(self):
|
|
170
|
+
r"""Returns the offset of the linear distribution.
|
|
171
|
+
|
|
172
|
+
Returns
|
|
173
|
+
-------
|
|
174
|
+
offset : float
|
|
175
|
+
The value of the distribution for the abscissa equal to 0.
|
|
176
|
+
"""
|
|
177
|
+
return self._offset
|
|
178
|
+
|
|
179
|
+
@offset.setter
|
|
180
|
+
def set_offset(self, x):
|
|
181
|
+
r"""Sets the offset of the linear distribution.
|
|
182
|
+
|
|
183
|
+
Parameters
|
|
184
|
+
----------
|
|
185
|
+
offset : float
|
|
186
|
+
The value of the distribution for the abscissa equal to 0.
|
|
187
|
+
"""
|
|
188
|
+
self._offset = x
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def slope(self):
|
|
192
|
+
r"""Returns the slope of the linear distribution.
|
|
193
|
+
|
|
194
|
+
Returns
|
|
195
|
+
-------
|
|
196
|
+
slope : float
|
|
197
|
+
The linear slope of the distribution w.r.t. the abscissa.
|
|
198
|
+
"""
|
|
199
|
+
return self._slope
|
|
200
|
+
|
|
201
|
+
@slope.setter
|
|
202
|
+
def set_slope(self, x):
|
|
203
|
+
r"""Sets the slope of the linear distribution.
|
|
204
|
+
|
|
205
|
+
Parameters
|
|
206
|
+
----------
|
|
207
|
+
slope : float
|
|
208
|
+
The linear slope of the distribution w.r.t. the abscissa.
|
|
209
|
+
"""
|
|
210
|
+
self._slope = x
|
|
211
|
+
|
|
212
|
+
class fermi_dirac(unique_distribution):
|
|
213
|
+
r"""Child class for Fermi-Dirac (FD) distributions, used e.g., during Fermi
|
|
214
|
+
edge fitting. The FD class is unique, only one instance should be used
|
|
215
|
+
per task.
|
|
216
|
+
|
|
217
|
+
The Fermi-Dirac distribution is described by the following formula:
|
|
218
|
+
|
|
219
|
+
.. math::
|
|
220
|
+
|
|
221
|
+
\frac{A}{\rm{e}^{\beta(E_{\rm{kin}}-(h\nu-\Phi))}+1} + B
|
|
222
|
+
|
|
223
|
+
with :math:`A` as :attr:`integrated_weight`, :math:`B` as
|
|
224
|
+
:attr:`background`, :math:`h\nu-\Phi` as :attr:`hnuminphi`, and
|
|
225
|
+
:math:`\beta=1/(k_{\rm{B}}T)` with :math:`T` as :attr:`temperature`.
|
|
226
|
+
|
|
227
|
+
Parameters
|
|
228
|
+
----------
|
|
229
|
+
temperature : float
|
|
230
|
+
Temperature of the sample [K]
|
|
231
|
+
hnuminphi : float
|
|
232
|
+
Kinetic energy minus the work function [eV]
|
|
233
|
+
background : float
|
|
234
|
+
Background spectral weight [counts]
|
|
235
|
+
integrated_weight : float
|
|
236
|
+
Integrated weight on top of the background [counts]
|
|
237
|
+
"""
|
|
238
|
+
def __init__(self, temperature, hnuminphi, background=0,
|
|
239
|
+
integrated_weight=1, name='fermi_dirac'):
|
|
240
|
+
super().__init__(name)
|
|
241
|
+
self.temperature = temperature
|
|
242
|
+
self.hnuminphi = hnuminphi
|
|
243
|
+
self.background = background
|
|
244
|
+
self.integrated_weight = integrated_weight
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def temperature(self):
|
|
248
|
+
r"""Returns the temperature of the sample.
|
|
249
|
+
|
|
250
|
+
Returns
|
|
251
|
+
-------
|
|
252
|
+
temperature : float
|
|
253
|
+
Temperature of the sample [K]
|
|
254
|
+
"""
|
|
255
|
+
return self._temperature
|
|
256
|
+
|
|
257
|
+
@temperature.setter
|
|
258
|
+
def set_temperature(self, x):
|
|
259
|
+
r"""Sets the temperature of the FD distribution.
|
|
260
|
+
|
|
261
|
+
Parameters
|
|
262
|
+
----------
|
|
263
|
+
temperature : float
|
|
264
|
+
Temperature of the sample [K]
|
|
265
|
+
"""
|
|
266
|
+
self._temperature = x
|
|
267
|
+
|
|
268
|
+
@property
|
|
269
|
+
def hnuminphi(self):
|
|
270
|
+
r"""Returns the photon energy minus the work function of the FD
|
|
271
|
+
distribution.
|
|
272
|
+
|
|
273
|
+
Returns
|
|
274
|
+
-------
|
|
275
|
+
hnuminphi: float
|
|
276
|
+
Kinetic energy minus the work function [eV]
|
|
277
|
+
"""
|
|
278
|
+
return self._hnuminphi
|
|
279
|
+
|
|
280
|
+
@hnuminphi.setter
|
|
281
|
+
def set_hnuminphi(self, x):
|
|
282
|
+
r"""Sets the photon energy minus the work function of the FD
|
|
283
|
+
distribution.
|
|
284
|
+
|
|
285
|
+
Parameters
|
|
286
|
+
----------
|
|
287
|
+
hnuminphi : float
|
|
288
|
+
Kinetic energy minus the work function [eV]
|
|
289
|
+
"""
|
|
290
|
+
self._hnuminphi = x
|
|
291
|
+
|
|
292
|
+
@property
|
|
293
|
+
def background(self):
|
|
294
|
+
r"""Returns the background intensity of the FD distribution.
|
|
295
|
+
|
|
296
|
+
Returns
|
|
297
|
+
-------
|
|
298
|
+
background : float
|
|
299
|
+
Background spectral weight [counts]
|
|
300
|
+
"""
|
|
301
|
+
return self._background
|
|
302
|
+
|
|
303
|
+
@background.setter
|
|
304
|
+
def set_background(self, x):
|
|
305
|
+
r"""Sets the background intensity of the FD distribution.
|
|
306
|
+
|
|
307
|
+
Parameters
|
|
308
|
+
----------
|
|
309
|
+
background : float
|
|
310
|
+
Background spectral weight [counts]
|
|
311
|
+
"""
|
|
312
|
+
self._background = x
|
|
313
|
+
|
|
314
|
+
@property
|
|
315
|
+
def integrated_weight(self):
|
|
316
|
+
r"""Returns the integrated weight of the FD distribution.
|
|
317
|
+
|
|
318
|
+
Returns
|
|
319
|
+
-------
|
|
320
|
+
integrated_weight: float
|
|
321
|
+
Integrated weight on top of the background [counts]
|
|
322
|
+
"""
|
|
323
|
+
return self._integrated_weight
|
|
324
|
+
|
|
325
|
+
@integrated_weight.setter
|
|
326
|
+
def set_integrated_weight(self, x):
|
|
327
|
+
r"""Sets the integrated weight of the FD distribution.
|
|
328
|
+
|
|
329
|
+
Parameters
|
|
330
|
+
----------
|
|
331
|
+
integrated_weight : float
|
|
332
|
+
Integrated weight on top of the background [counts]
|
|
333
|
+
"""
|
|
334
|
+
self._integrated_weight = x
|
|
335
|
+
|
|
336
|
+
def __call__(self, energy_range, hnuminphi, background, integrated_weight,
|
|
337
|
+
energy_resolution):
|
|
338
|
+
"""Call method to directly evaluate a FD distribution without having to
|
|
339
|
+
instantiate a class instance.
|
|
340
|
+
|
|
341
|
+
Parameters
|
|
342
|
+
----------
|
|
343
|
+
energy_range : ndarray
|
|
344
|
+
1D array on which to evaluate the FD distribution [eV]
|
|
345
|
+
hnuminphi : float
|
|
346
|
+
Kinetic energy minus the work function [eV]
|
|
347
|
+
background : float
|
|
348
|
+
Background spectral weight [counts]
|
|
349
|
+
integrated_weight : float
|
|
350
|
+
Integrated weight on top of the background [counts]
|
|
351
|
+
energy_resolution : float
|
|
352
|
+
Energy resolution of the detector for the convolution [eV]
|
|
353
|
+
|
|
354
|
+
Returns
|
|
355
|
+
-------
|
|
356
|
+
evalf : ndarray
|
|
357
|
+
1D array of the energy-convolved FD distribution [counts]
|
|
358
|
+
"""
|
|
359
|
+
from scipy.ndimage import gaussian_filter
|
|
360
|
+
import numpy as np
|
|
361
|
+
sigma_extend = 5 # Extend data range by "5 sigma"
|
|
362
|
+
# Conversion from FWHM to standard deviation [-]
|
|
363
|
+
fwhm_to_std = np.sqrt(8 * np.log(2))
|
|
364
|
+
k_B = 8.617e-5 # Boltzmann constant [eV/K]
|
|
365
|
+
k_BT = self.temperature * k_B
|
|
366
|
+
step_size = np.abs(energy_range[1] - energy_range[0])
|
|
367
|
+
estep = energy_resolution / (step_size * fwhm_to_std)
|
|
368
|
+
enumb = int(sigma_extend * estep)
|
|
369
|
+
extend = np.linspace(energy_range[0] - enumb * step_size,
|
|
370
|
+
energy_range[-1] + enumb * step_size,
|
|
371
|
+
len(energy_range) + 2 * enumb)
|
|
372
|
+
result = (integrated_weight / (1 + np.exp((extend - hnuminphi) / k_BT))
|
|
373
|
+
+ background)
|
|
374
|
+
evalf = gaussian_filter(result, sigma=estep)[enumb:-enumb]
|
|
375
|
+
return evalf
|
|
376
|
+
|
|
377
|
+
def evaluate(self, energy_range):
|
|
378
|
+
r"""Evaluates the FD distribution for a given class instance.
|
|
379
|
+
No energy convolution is performed with evaluate.
|
|
380
|
+
|
|
381
|
+
Parameters
|
|
382
|
+
----------
|
|
383
|
+
energy_range : ndarray
|
|
384
|
+
1D array on which to evaluate the FD distribution [eV]
|
|
385
|
+
|
|
386
|
+
Returns
|
|
387
|
+
-------
|
|
388
|
+
evalf : ndarray
|
|
389
|
+
1D array of the evaluated FD distribution [counts]
|
|
390
|
+
"""
|
|
391
|
+
import numpy as np
|
|
392
|
+
k_B = 8.617e-5 # Boltzmann constant [eV/K]
|
|
393
|
+
k_BT = self.temperature * k_B
|
|
394
|
+
evalf = (self.integrated_weight
|
|
395
|
+
/ (1 + np.exp((energy_range - self.hnuminphi) / k_BT))
|
|
396
|
+
+ self.background)
|
|
397
|
+
return evalf
|
|
398
|
+
|
|
399
|
+
def convolve(self, energy_range, energy_resolution):
|
|
400
|
+
r"""Evaluates the FD distribution for a given class instance and
|
|
401
|
+
performs the energy convolution with the given resolution. The
|
|
402
|
+
convolution is performed with an expanded abscissa range of 5
|
|
403
|
+
times the standard deviation.
|
|
404
|
+
|
|
405
|
+
Parameters
|
|
406
|
+
----------
|
|
407
|
+
energy_range : ndarray
|
|
408
|
+
1D array on which to evaluate and convolve FD distribution [eV]
|
|
409
|
+
energy_resolution : float
|
|
410
|
+
Energy resolution of the detector for the convolution [eV]
|
|
411
|
+
|
|
412
|
+
Returns
|
|
413
|
+
-------
|
|
414
|
+
evalf : ndarray
|
|
415
|
+
1D array of the energy-convolved FD distribution [counts]
|
|
416
|
+
"""
|
|
417
|
+
import numpy as np
|
|
418
|
+
from scipy.ndimage import gaussian_filter
|
|
419
|
+
sigma_extend = 5 # Extend data range by "5 sigma"
|
|
420
|
+
# Conversion from FWHM to standard deviation [-]
|
|
421
|
+
fwhm_to_std = np.sqrt(8 * np.log(2))
|
|
422
|
+
step_size = np.abs(energy_range[1] - energy_range[0])
|
|
423
|
+
estep = energy_resolution / (step_size * fwhm_to_std)
|
|
424
|
+
enumb = int(sigma_extend * estep)
|
|
425
|
+
extend = np.linspace(energy_range[0] - enumb * step_size,
|
|
426
|
+
energy_range[-1] + enumb * step_size,
|
|
427
|
+
len(energy_range) + 2 * enumb)
|
|
428
|
+
evalf = gaussian_filter(self.evaluate(extend),
|
|
429
|
+
sigma=estep)[enumb:-enumb]
|
|
430
|
+
return evalf
|