Source code for aiida_quantumespresso.calculations.functions.xspectra.get_xps_spectra
# -*- coding: utf-8 -*-
"""CalcFunction to compute the spectrum from ``XpsWorkchain``."""
import warnings
from aiida import orm
from aiida.engine import calcfunction
import numpy as np
warnings.warn(
'This module is deprecated and will be removed soon as part of migrating XAS and XPS workflows to a new repository.'
'\nThe new repository can be found at: https://github.com/aiidaplugins/aiida-qe-xspec.', FutureWarning
)
@calcfunction
[docs]def get_spectra_by_element(elements_list, equivalent_sites_data, voight_gamma, voight_sigma, **kwargs): # pylint: disable=too-many-statements
"""Generate the XPS spectra for each element.
Calculate the core level shift and binding energy for each element.
Generate the final spectra using the Voigt profile.
:param elements_list: a List object defining the list of elements to consider
when producing spectrum.
:param equivalent_sites_data: an Dict object containing symmetry data.
:param voight_gamma: a Float node for the gamma parameter of the voigt profile.
:param voight_sigma: a Float node for the sigma parameter of the voigt profile.
:param structure: the StructureData object to be analysed
:returns: Dict objects for all generated spectra and associated binding energy
and core level shift.
"""
from scipy.special import voigt_profile # pylint: disable=no-name-in-module
ground_state_node = kwargs.pop('ground_state', None)
correction_energies = kwargs.pop('correction_energies', orm.Dict()).get_dict()
incoming_param_nodes = {key: value for key, value in kwargs.items() if key != 'metadata'}
group_state_energy = None
if ground_state_node is not None:
group_state_energy = ground_state_node.get_dict()['energy']
elements = elements_list.get_list()
sigma = voight_sigma.value
gamma = voight_gamma.value
equivalency_data = equivalent_sites_data.get_dict()
data_dict = {element: {} for element in elements}
for key in incoming_param_nodes:
xspectra_out_params = incoming_param_nodes[key].get_dict()
multiplicity = equivalency_data[key]['multiplicity']
element = equivalency_data[key]['symbol']
total_energy = xspectra_out_params['energy']
data_dict[element][key] = {'element': element, 'multiplicity': multiplicity, 'total_energy': total_energy}
result = {}
core_level_shifts = {}
binding_energies = {}
for element in elements:
spectra_list = []
for key in data_dict[element]:
site_multiplicity = data_dict[element][key]['multiplicity']
spectra_list.append((site_multiplicity, float(data_dict[element][key]['total_energy']), key))
spectra_list.sort(key=lambda entry: entry[1])
lowest_total_energy = spectra_list[0][1]
core_level_shift = [(entry[0], entry[1] - lowest_total_energy, entry[2]) for entry in spectra_list]
core_level_shifts[element] = core_level_shift
result[f'{element}_cls'] = orm.Dict(dict={entry[2]: entry[1] for entry in core_level_shift})
if group_state_energy is not None:
binding_energy = [(entry[0], entry[1] - group_state_energy + correction_energies[element], entry[2])
for entry in spectra_list]
binding_energies[element] = binding_energy
result[f'{element}_be'] = orm.Dict(dict={entry[2]: entry[1] for entry in binding_energy})
fwhm_voight = gamma / 2 + np.sqrt(gamma**2 / 4 + sigma**2)
def spectra_broadening(points, label='cls_spectra'):
"""Broadening base on the binding energy."""
result_spectra = {}
for element in elements:
final_spectra_y_arrays = []
final_spectra_y_labels = []
final_spectra_y_units = []
total_multiplicity = sum(i[0] for i in points[element])
final_spectra = orm.XyData()
max_core_level_shift = points[element][-1][1]
min_core_level_shift = points[element][0][1]
# Energy range for the Broadening function
x_energy_range = np.linspace(
min_core_level_shift - fwhm_voight - 1.5, max_core_level_shift + fwhm_voight + 1.5, 500
)
for atoms, index in zip(points[element], range(len(points[element]))):
# Weight for the spectra of every atom
intensity = atoms[0]
relative_peak_position = atoms[1]
final_spectra_y_labels.append(f'{element}{index}_xps')
final_spectra_y_units.append('sigma')
final_spectra_y_arrays.append(
intensity * voigt_profile(x_energy_range - relative_peak_position, sigma, gamma) /
total_multiplicity
)
final_spectra_y_labels.append(f'{element}_total_xps')
final_spectra_y_units.append('sigma')
final_spectra_y_arrays.append(sum(final_spectra_y_arrays))
final_spectra_x_label = 'energy'
final_spectra_x_units = 'eV'
final_spectra_x_array = x_energy_range
final_spectra.set_x(final_spectra_x_array, final_spectra_x_label, final_spectra_x_units)
final_spectra.set_y(final_spectra_y_arrays, final_spectra_y_labels, final_spectra_y_units)
result_spectra[f'{element}_{label}'] = final_spectra
return result_spectra
result.update(spectra_broadening(core_level_shifts))
if ground_state_node is not None:
result.update(spectra_broadening(binding_energies, label='be_spectra'))
return result