Source code for aiida_quantumespresso.calculations.functions.xspectra.get_xps_spectra

# -*- coding: utf-8 -*-
"""CalcFunction to compute the spectrum from ``XpsWorkchain``."""
from aiida import orm
from aiida.engine import calcfunction
import numpy as np


@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