xarpes 0.1.0__py3-none-any.whl → 0.2.0__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.0.dist-info/LICENSE +674 -0
- {xarpes-0.1.0.dist-info → xarpes-0.2.0.dist-info}/METADATA +8 -1
- xarpes-0.2.0.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.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# Copyright (C) 2024 xARPES Developers
|
|
2
|
+
# This program is free software under the terms of the GNU GPLv3 license.
|
|
3
|
+
|
|
4
|
+
"""Separate functions mostly used in conjunction with various classes."""
|
|
5
|
+
|
|
6
|
+
def download_examples():
|
|
7
|
+
"""Downloads the examples folder from the xARPES code only if it does not
|
|
8
|
+
already exist. Prints executed steps and a final cleanup/failure message.
|
|
9
|
+
|
|
10
|
+
Returns
|
|
11
|
+
-------
|
|
12
|
+
0, 1 : int
|
|
13
|
+
Returns 0 if the execution succeeds, 1 if it fails.
|
|
14
|
+
"""
|
|
15
|
+
import requests
|
|
16
|
+
import zipfile
|
|
17
|
+
import os
|
|
18
|
+
import shutil
|
|
19
|
+
import io
|
|
20
|
+
|
|
21
|
+
repo_url = 'https://github.com/xARPES/xARPES_examples'
|
|
22
|
+
output_dir = '.' # Directory from which the function is called
|
|
23
|
+
|
|
24
|
+
# Check if 'examples' directory already exists
|
|
25
|
+
final_examples_path = os.path.join(output_dir, 'examples')
|
|
26
|
+
if os.path.exists(final_examples_path):
|
|
27
|
+
print("Warning: 'examples' folder already exists. No download will be performed.")
|
|
28
|
+
return 1 # Exit the function if 'examples' directory exists
|
|
29
|
+
|
|
30
|
+
# Proceed with download if 'examples' directory does not exist
|
|
31
|
+
repo_parts = repo_url.replace("https://github.com/", "").rstrip('/')
|
|
32
|
+
zip_url = f"https://github.com/{repo_parts}/archive/refs/heads/main.zip"
|
|
33
|
+
|
|
34
|
+
# Make the HTTP request to download the zip file
|
|
35
|
+
print(f"Downloading {zip_url}")
|
|
36
|
+
response = requests.get(zip_url)
|
|
37
|
+
if response.status_code == 200:
|
|
38
|
+
zip_file_bytes = io.BytesIO(response.content)
|
|
39
|
+
|
|
40
|
+
with zipfile.ZipFile(zip_file_bytes, 'r') as zip_ref:
|
|
41
|
+
zip_ref.extractall(output_dir)
|
|
42
|
+
|
|
43
|
+
# Path to the extracted main folder
|
|
44
|
+
main_folder_path = os.path.join(output_dir, repo_parts.split('/')[-1] + '-main')
|
|
45
|
+
examples_path = os.path.join(main_folder_path, 'examples')
|
|
46
|
+
|
|
47
|
+
# Move the 'examples' directory to the target location if it was extracted
|
|
48
|
+
if os.path.exists(examples_path):
|
|
49
|
+
shutil.move(examples_path, final_examples_path)
|
|
50
|
+
print(f"'examples' subdirectory moved to {final_examples_path}")
|
|
51
|
+
else:
|
|
52
|
+
print("'examples' subdirectory not found in the repository.")
|
|
53
|
+
|
|
54
|
+
# Remove the rest of the extracted content
|
|
55
|
+
shutil.rmtree(main_folder_path)
|
|
56
|
+
print(f"Cleaned up temporary files in {main_folder_path}")
|
|
57
|
+
return 0
|
|
58
|
+
else:
|
|
59
|
+
print(f"Failed to download the repository. Status code: {response.status_code}")
|
|
60
|
+
return 1
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def error_function(p, xdata, ydata, function, extra_args):
|
|
64
|
+
r"""The error function used inside the fit_leastsq function.
|
|
65
|
+
|
|
66
|
+
Parameters
|
|
67
|
+
----------
|
|
68
|
+
p : ndarray
|
|
69
|
+
Array of parameters during the optimization
|
|
70
|
+
xdata : ndarray
|
|
71
|
+
Array of abscissa values the function is evaluated on
|
|
72
|
+
ydata : ndarray
|
|
73
|
+
Outcomes on ordinate the evaluated function is compared to
|
|
74
|
+
function : function
|
|
75
|
+
Function or class with call method to be evaluated
|
|
76
|
+
extra_args :
|
|
77
|
+
Arguments provided to function that should not be optimized
|
|
78
|
+
|
|
79
|
+
Returns
|
|
80
|
+
-------
|
|
81
|
+
residual :
|
|
82
|
+
Residual between evaluated function and ydata
|
|
83
|
+
"""
|
|
84
|
+
residual = function(xdata, *p, extra_args) - ydata
|
|
85
|
+
return residual
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def fit_leastsq(p0, xdata, ydata, function, extra_args):
|
|
89
|
+
r"""Wrapper arround scipy.optimize.leastsq.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
p0 : ndarray
|
|
94
|
+
Initial guess for parameters to be optimized
|
|
95
|
+
xdata : ndarray
|
|
96
|
+
Array of abscissa values the function is evaluated on
|
|
97
|
+
ydata : ndarray
|
|
98
|
+
Outcomes on ordinate the evaluated function is compared to
|
|
99
|
+
function : function
|
|
100
|
+
Function or class with call method to be evaluated
|
|
101
|
+
extra_args :
|
|
102
|
+
Arguments provided to function that should not be optimized
|
|
103
|
+
|
|
104
|
+
Returns
|
|
105
|
+
-------
|
|
106
|
+
pfit_leastsq : ndarray
|
|
107
|
+
Array containing the optimized parameters
|
|
108
|
+
perr_leastsq : ndarray
|
|
109
|
+
Covariance matrix of the optimized parameters
|
|
110
|
+
"""
|
|
111
|
+
import numpy as np
|
|
112
|
+
from scipy.optimize import leastsq
|
|
113
|
+
pfit, pcov, infodict, errmsg, success = leastsq(
|
|
114
|
+
error_function, p0, args=(xdata, ydata, function, extra_args),
|
|
115
|
+
full_output=1)
|
|
116
|
+
|
|
117
|
+
if (len(ydata) > len(p0)) and pcov is not None:
|
|
118
|
+
s_sq = (error_function(pfit, xdata, ydata, function,
|
|
119
|
+
extra_args) ** 2).sum() / (len(ydata) - len(p0))
|
|
120
|
+
pcov = pcov * s_sq
|
|
121
|
+
else:
|
|
122
|
+
pcov = np.inf
|
|
123
|
+
|
|
124
|
+
error = []
|
|
125
|
+
for i in range(len(pfit)):
|
|
126
|
+
try:
|
|
127
|
+
error.append(np.absolute(pcov[i][i]) ** 0.5)
|
|
128
|
+
except:
|
|
129
|
+
error.append(0.00)
|
|
130
|
+
pfit_leastsq = pfit
|
|
131
|
+
perr_leastsq = np.array(error)
|
|
132
|
+
|
|
133
|
+
return pfit_leastsq, perr_leastsq
|
|
@@ -0,0 +1,157 @@
|
|
|
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
|
+
"""Functions related to plotting."""
|
|
13
|
+
|
|
14
|
+
from functools import wraps
|
|
15
|
+
import matplotlib.pyplot as plt
|
|
16
|
+
import matplotlib as mpl
|
|
17
|
+
|
|
18
|
+
def plot_settings(name='default'):
|
|
19
|
+
mpl.rc('xtick', labelsize=10, direction='in')
|
|
20
|
+
mpl.rc('ytick', labelsize=10, direction='in')
|
|
21
|
+
lw = dict(default=2.0, large=4.0)[name]
|
|
22
|
+
mpl.rcParams['lines.linewidth'] = lw
|
|
23
|
+
mpl.rcParams['lines.markersize'] = 3
|
|
24
|
+
mpl.rcParams['xtick.major.size'] = 4
|
|
25
|
+
mpl.rcParams['xtick.minor.size'] = 2
|
|
26
|
+
mpl.rcParams['xtick.major.width'] = 0.8
|
|
27
|
+
mpl.rcParams.update({'font.size': 16})
|
|
28
|
+
|
|
29
|
+
def get_ax_fig_plt(ax=None, **kwargs):
|
|
30
|
+
r"""Helper function used in plot functions supporting an optional `Axes`
|
|
31
|
+
argument.
|
|
32
|
+
|
|
33
|
+
If `ax` is `None`, we build the `matplotlib` figure and create the `Axes`.
|
|
34
|
+
Else we return the current active figure.
|
|
35
|
+
|
|
36
|
+
Parameters
|
|
37
|
+
----------
|
|
38
|
+
ax : object
|
|
39
|
+
`Axes` object. Defaults to `None`.
|
|
40
|
+
**kwargs
|
|
41
|
+
Keyword arguments are passed to `plt.figure` if `ax` is not `None`.
|
|
42
|
+
|
|
43
|
+
Returns
|
|
44
|
+
-------
|
|
45
|
+
ax : object
|
|
46
|
+
`Axes` object.
|
|
47
|
+
figure : object
|
|
48
|
+
`matplotlib` figure.
|
|
49
|
+
plt : object
|
|
50
|
+
`matplotlib.pyplot` module.
|
|
51
|
+
"""
|
|
52
|
+
if ax is None:
|
|
53
|
+
fig = plt.figure(**kwargs)
|
|
54
|
+
ax = fig.gca()
|
|
55
|
+
else:
|
|
56
|
+
fig = plt.gcf()
|
|
57
|
+
|
|
58
|
+
return ax, fig, plt
|
|
59
|
+
|
|
60
|
+
def add_fig_kwargs(func):
|
|
61
|
+
"""Decorator that adds keyword arguments for functions returning matplotlib
|
|
62
|
+
figures.
|
|
63
|
+
|
|
64
|
+
The function should return either a matplotlib figure or None to signal
|
|
65
|
+
some sort of error/unexpected event.
|
|
66
|
+
"""
|
|
67
|
+
@wraps(func)
|
|
68
|
+
def wrapper(*args, **kwargs):
|
|
69
|
+
# pop the kwds used by the decorator.
|
|
70
|
+
title = kwargs.pop('title', None)
|
|
71
|
+
size_kwargs = kwargs.pop('size_kwargs', None)
|
|
72
|
+
show = kwargs.pop('show', True)
|
|
73
|
+
savefig = kwargs.pop('savefig', None)
|
|
74
|
+
tight_layout = kwargs.pop('tight_layout', False)
|
|
75
|
+
ax_grid = kwargs.pop('ax_grid', None)
|
|
76
|
+
ax_annotate = kwargs.pop('ax_annotate', None)
|
|
77
|
+
fig_close = kwargs.pop('fig_close', False)
|
|
78
|
+
|
|
79
|
+
# Call func and return immediately if None is returned.
|
|
80
|
+
fig = func(*args, **kwargs)
|
|
81
|
+
if fig is None:
|
|
82
|
+
return fig
|
|
83
|
+
|
|
84
|
+
# Operate on matplotlib figure.
|
|
85
|
+
if title is not None:
|
|
86
|
+
fig.suptitle(title)
|
|
87
|
+
|
|
88
|
+
if size_kwargs is not None:
|
|
89
|
+
fig.set_size_inches(size_kwargs.pop('w'), size_kwargs.pop('h'),
|
|
90
|
+
**size_kwargs)
|
|
91
|
+
|
|
92
|
+
if ax_grid is not None:
|
|
93
|
+
for ax in fig.axes:
|
|
94
|
+
ax.grid(bool(ax_grid))
|
|
95
|
+
|
|
96
|
+
if ax_annotate:
|
|
97
|
+
tags = ascii_letters
|
|
98
|
+
if len(fig.axes) > len(tags):
|
|
99
|
+
tags = (1 + len(ascii_letters) // len(fig.axes)) * ascii_letters
|
|
100
|
+
for ax, tag in zip(fig.axes, tags):
|
|
101
|
+
ax.annotate(f'({tag})', xy=(0.05, 0.95),
|
|
102
|
+
xycoords='axes fraction')
|
|
103
|
+
|
|
104
|
+
if tight_layout:
|
|
105
|
+
try:
|
|
106
|
+
fig.tight_layout()
|
|
107
|
+
except Exception as exc:
|
|
108
|
+
# For some unknown reason, this problem shows up only on travis.
|
|
109
|
+
# https://stackoverflow.com/questions/22708888/valueerror-when-using-matplotlib-tight-layout
|
|
110
|
+
print('Ignoring Exception raised by fig.tight_layout\n',
|
|
111
|
+
str(exc))
|
|
112
|
+
|
|
113
|
+
if savefig:
|
|
114
|
+
fig.savefig(savefig)
|
|
115
|
+
|
|
116
|
+
if show:
|
|
117
|
+
plt.show()
|
|
118
|
+
if fig_close:
|
|
119
|
+
plt.close(fig=fig)
|
|
120
|
+
|
|
121
|
+
return fig
|
|
122
|
+
|
|
123
|
+
# Add docstring to the decorated method.
|
|
124
|
+
doc_str = """\n\n
|
|
125
|
+
|
|
126
|
+
notes
|
|
127
|
+
-----
|
|
128
|
+
|
|
129
|
+
Keyword arguments controlling the display of the figure:
|
|
130
|
+
|
|
131
|
+
================ ====================================================
|
|
132
|
+
kwargs Meaning
|
|
133
|
+
================ ====================================================
|
|
134
|
+
title Title of the plot (Default: None).
|
|
135
|
+
show True to show the figure (default: True).
|
|
136
|
+
savefig "abc.png" or "abc.eps" to save the figure to a file.
|
|
137
|
+
size_kwargs Dictionary with options passed to fig.set_size_inches
|
|
138
|
+
e.g. size_kwargs=dict(w=3, h=4)
|
|
139
|
+
tight_layout True to call fig.tight_layout (default: False)
|
|
140
|
+
ax_grid True (False) to add (remove) grid from all axes in
|
|
141
|
+
fig.
|
|
142
|
+
Default: None i.e. fig is left unchanged.
|
|
143
|
+
ax_annotate Add labels to subplots e.g. (a), (b).
|
|
144
|
+
Default: False
|
|
145
|
+
fig_close Close figure. Default: False.
|
|
146
|
+
================ ====================================================
|
|
147
|
+
|
|
148
|
+
"""
|
|
149
|
+
|
|
150
|
+
if wrapper.__doc__ is not None:
|
|
151
|
+
# Add s at the end of the docstring.
|
|
152
|
+
wrapper.__doc__ += f'\n{doc_str}'
|
|
153
|
+
else:
|
|
154
|
+
# Use s
|
|
155
|
+
wrapper.__doc__ = doc_str
|
|
156
|
+
|
|
157
|
+
return wrapper
|
xarpes/__init__.py
CHANGED
xarpes/band_map.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
# Copyright (C) 2024 xARPES Developers
|
|
2
|
-
# This program is free software under the terms of the GNU
|
|
2
|
+
# This program is free software under the terms of the GNU GPLv3 license.
|
|
3
3
|
|
|
4
4
|
# get_ax_fig_plt and add_fig_kwargs originate from pymatgen/util/plotting.py.
|
|
5
5
|
# Copyright (C) 2011-2024 Shyue Ping Ong and the pymatgen Development Team
|
|
@@ -28,43 +28,72 @@ class band_map():
|
|
|
28
28
|
1D array of kinetic energy values for the ordinate [eV]
|
|
29
29
|
energy_resolution : float
|
|
30
30
|
Energy resolution of the detector [eV]
|
|
31
|
-
temperature : float
|
|
31
|
+
temperature : float, None
|
|
32
32
|
Temperature of the sample [K]
|
|
33
|
-
hnuminphi : float
|
|
33
|
+
hnuminphi : float, None
|
|
34
34
|
Kinetic energy minus the work function [eV]
|
|
35
|
+
hnuminphi_std : float, None
|
|
36
|
+
Standard deviation of kinetic energy minus work function [eV]
|
|
35
37
|
"""
|
|
36
38
|
def __init__(self, intensities, angles, ekin, energy_resolution=None,
|
|
37
|
-
temperature=None, hnuminphi=None):
|
|
38
|
-
|
|
39
|
+
temperature=None, hnuminphi=None, hnuminphi_std=None):
|
|
39
40
|
self.intensities = intensities
|
|
40
41
|
self.angles = angles
|
|
41
42
|
self.ekin = ekin
|
|
42
43
|
self.energy_resolution = energy_resolution
|
|
43
44
|
self.temperature = temperature
|
|
44
45
|
self.hnuminphi = hnuminphi
|
|
46
|
+
self.hnuminphi_std = hnuminphi_std
|
|
45
47
|
|
|
46
48
|
@property
|
|
47
49
|
def hnuminphi(self):
|
|
48
|
-
r"""Returns the photon energy minus the work function in eV
|
|
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.
|
|
49
53
|
|
|
50
54
|
Returns
|
|
51
55
|
-------
|
|
52
|
-
hnuminphi : float
|
|
56
|
+
hnuminphi : float, None
|
|
53
57
|
Kinetic energy minus the work function [eV]
|
|
54
58
|
"""
|
|
55
59
|
return self._hnuminphi
|
|
56
60
|
|
|
57
61
|
@hnuminphi.setter
|
|
58
62
|
def hnuminphi(self, hnuminphi):
|
|
59
|
-
r"""Manually sets the photon energy minus the work function in eV
|
|
63
|
+
r"""Manually sets the photon energy minus the work function in eV if it
|
|
64
|
+
has been set; otherwise returns None.
|
|
60
65
|
|
|
61
66
|
Parameters
|
|
62
67
|
----------
|
|
63
|
-
hnuminphi : float
|
|
68
|
+
hnuminphi : float, None
|
|
64
69
|
Kinetic energy minus the work function [eV]
|
|
65
70
|
"""
|
|
66
71
|
self._hnuminphi = hnuminphi
|
|
67
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
|
+
|
|
68
97
|
def shift_angles(self, shift):
|
|
69
98
|
r"""
|
|
70
99
|
Shifts the angles by the specified amount in degrees. Used to shift
|
|
@@ -84,6 +113,9 @@ class band_map():
|
|
|
84
113
|
ekin_max=np.infty, ax=None, **kwargs):
|
|
85
114
|
r"""
|
|
86
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.
|
|
87
119
|
|
|
88
120
|
Parameters
|
|
89
121
|
----------
|
|
@@ -104,13 +136,17 @@ class band_map():
|
|
|
104
136
|
ax : Matplotlib-Axes / NoneType
|
|
105
137
|
Axis for plotting the Fermi edge on. Created if not provided by
|
|
106
138
|
the user.
|
|
139
|
+
|
|
140
|
+
Other parameters
|
|
141
|
+
----------------
|
|
107
142
|
**kwargs : dict, optional
|
|
108
143
|
Additional arguments passed on to add_fig_kwargs. See the keyword
|
|
109
144
|
table below.
|
|
110
145
|
|
|
111
146
|
Returns
|
|
112
147
|
-------
|
|
113
|
-
Matplotlib-Figure
|
|
148
|
+
fig : Matplotlib-Figure
|
|
149
|
+
Figure containing the Fermi edge fit
|
|
114
150
|
"""
|
|
115
151
|
from xarpes.functions import fit_leastsq
|
|
116
152
|
|
|
@@ -148,6 +184,7 @@ class band_map():
|
|
|
148
184
|
name='Fitted result')
|
|
149
185
|
|
|
150
186
|
self.hnuminphi = popt[0]
|
|
187
|
+
self.hnuminphi_std = np.sqrt(np.diag(pcov))[0][0]
|
|
151
188
|
|
|
152
189
|
ax.set_xlabel(r'$E_{\mathrm{kin}}$ (-)')
|
|
153
190
|
ax.set_ylabel('Counts (-)')
|
|
@@ -165,4 +202,4 @@ class band_map():
|
|
|
165
202
|
|
|
166
203
|
ax.legend()
|
|
167
204
|
|
|
168
|
-
return fig
|
|
205
|
+
return fig
|