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

# -*- coding: utf-8 -*-
"""Calcfunction to compile a complete spectrum for each element from multiple powder sample spectra."""
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, **kwargs): """Generate a final spectrum for each element from a dictionary of powder spectra inputs. Powder spectra to be processed must be passed in using ``kwargs``, in which the keys must correspond to the keys of ``equivalent_sites_data``. :param elements_list: a List object defining the elements to compile spectra for. :param equivalent_sites_data: a Dict object, defining the symmetry properties of the sites associated with each powder spectrum in ``kwargs``. Must be in the format used in the ``equivalent_sites_data`` dictionary of ``get_xspectra_structures.outputs.output_parameters`` """ incoming_spectra_nodes = {key: value for key, value in kwargs.items() if key != 'metadata'} elements = elements_list.get_list() equivalency_data = equivalent_sites_data.get_dict() core_work_chains = {key: value.creator.caller for key, value in incoming_spectra_nodes.items()} data_dict = {element: {} for element in elements} for key in incoming_spectra_nodes: core_work_chain = core_work_chains[key] xspectra_out_params = core_work_chain.outputs.parameters_xspectra__xas_0.get_dict() energy_zero = xspectra_out_params['energy_zero'] multiplicity = equivalency_data[key]['multiplicity'] element = equivalency_data[key]['symbol'] if 'total_multiplicity' not in data_dict[element]: data_dict[element]['total_multiplicity'] = multiplicity else: data_dict[element]['total_multiplicity'] += multiplicity data_dict[element][key] = { 'spectrum_node': incoming_spectra_nodes[key], 'element': element, 'multiplicity': multiplicity, 'energy_zero': energy_zero } spectra_by_element = {} for element in elements: spectra_list = [] total_multiplicity = data_dict[element].pop('total_multiplicity') for key in data_dict[element]: spectrum_node = data_dict[element][key]['spectrum_node'] site_multiplicity = data_dict[element][key]['multiplicity'] spectrum_x = spectrum_node.get_x()[1] spectrum_y = spectrum_node.get_y()[0][1] weighted_spectrum = np.column_stack((spectrum_x, (spectrum_y * site_multiplicity) / total_multiplicity)) spectra_list.append((weighted_spectrum, float(data_dict[element][key]['energy_zero']))) # Sort according to Fermi level, then correct to align all spectra to the # highest value. Note that this is needed because XSpectra automatically aligns the # final spectrum such that the system's Fermi level is at 0 eV. spectra_list.sort(key=lambda entry: entry[1]) highest_level = spectra_list[0][-1] energy_zero_corrections = [(entry[0], entry[1] - highest_level) for entry in spectra_list] corrected_spectra = [ np.column_stack((entry[0][:, 0] - entry[1], entry[0][:, 1])) for entry in energy_zero_corrections ] spectra_by_element[element] = np.column_stack(( sum(array[:, 0] for array in corrected_spectra) / len(corrected_spectra), sum(array[:, 1] for array in corrected_spectra) )) all_final_spectra = {} for element in elements: final_spectra = orm.XyData() corrected_spectrum = spectra_by_element[element] final_spectra_y_labels = [f'{element}_dipole'] final_spectra_y_units = ['sigma'] final_spectra_y_arrays = [corrected_spectrum[:, 1]] final_spectra_x_label = 'energy' final_spectra_x_units = 'eV' final_spectra_x_array = corrected_spectrum[:, 0] 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) all_final_spectra[f'{element}_xas'] = final_spectra return all_final_spectra