Ejemplo n.º 1
0
    def _parse_stdout(self, out_folder):
        """CP2K output parser"""

        from aiida.orm import BandsData, Dict

        # pylint: disable=protected-access

        fname = self.node.process_class._DEFAULT_OUTPUT_FILE
        if fname not in out_folder._repository.list_object_names():
            raise OutputParsingError("Cp2k output file not retrieved")

        abs_fn = os.path.join(
            out_folder._repository._get_base_folder().abspath, fname)

        with io.open(abs_fn, mode="r", encoding="utf-8") as fobj:
            result_dict = parse_cp2k_output(fobj)

        if "nwarnings" not in result_dict:
            raise OutputParsingError("CP2K did not finish properly.")

        if "kpoint_data" in result_dict:
            bnds = BandsData()
            bnds.set_kpoints(result_dict["kpoint_data"]["kpoints"])
            bnds.labels = result_dict["kpoint_data"]["labels"]
            bnds.set_bands(
                result_dict["kpoint_data"]["bands"],
                units=result_dict["kpoint_data"]["bands_unit"],
            )
            self.out("output_bands", bnds)
            del result_dict["kpoint_data"]

        self.out("output_parameters", Dict(dict=result_dict))
Ejemplo n.º 2
0
def example_bands_v2(fresh_aiida_env):
    """Example eigen values and occupations"""
    from aiida.orm import BandsData
    bdata = BandsData()
    bdata.set_kpoints([[0, 0, 0], [0.25, 0.25, 0.25]])
    occ = np.array([[1, 1, 1, 0, 0, 0], [1, 1, 1, 0, 0, 0]], dtype=np.float64)
    eigen = np.array([[-1, -1, -1, 0, 0, 0], [-0.5, -0.5, -0.5, 0, 0, 0]])
    bdata.set_bands(bands=eigen, occupations=occ)
    return bdata
Ejemplo n.º 3
0
    def _parse_stdout(self):
        """Advanced CP2K output file parser."""

        from aiida.orm import BandsData
        from aiida_cp2k.utils import parse_cp2k_output_advanced

        fname = self.node.process_class._DEFAULT_OUTPUT_FILE  # pylint: disable=protected-access
        if fname not in self.retrieved.list_object_names():
            raise OutputParsingError("Cp2k output file not retrieved")

        try:
            output_string = self.retrieved.get_object_content(fname)
        except IOError:
            return self.exit_codes.ERROR_OUTPUT_STDOUT_READ

        result_dict = parse_cp2k_output_advanced(output_string)

        # nwarnings is the last thing to be printed in th eCP2K output file:
        # if it is not there, CP2K didn't finish properly
        if 'nwarnings' not in result_dict:
            raise OutputParsingError("CP2K did not finish properly.")

        if "aborted" in result_dict:
            return self.exit_codes.ERROR_OUTPUT_CONTAINS_ABORT

        # Compute the bandgap for Spin1 and Spin2 if eigen was parsed (works also with smearing!)
        if 'eigen_spin1_au' in result_dict:
            if result_dict['dft_type'] == "RKS":
                result_dict['eigen_spin2_au'] = result_dict['eigen_spin1_au']

            lumo_spin1_idx = result_dict['init_nel_spin1']
            lumo_spin2_idx = result_dict['init_nel_spin2']
            if (lumo_spin1_idx > len(result_dict['eigen_spin1_au'])-1) or \
               (lumo_spin2_idx > len(result_dict['eigen_spin2_au'])-1):
                #electrons jumped from spin1 to spin2 (or opposite): assume last eigen is lumo
                lumo_spin1_idx = len(result_dict['eigen_spin1_au']) - 1
                lumo_spin2_idx = len(result_dict['eigen_spin2_au']) - 1
            homo_spin1 = result_dict['eigen_spin1_au'][lumo_spin1_idx - 1]
            homo_spin2 = result_dict['eigen_spin2_au'][lumo_spin2_idx - 1]
            lumo_spin1 = result_dict['eigen_spin1_au'][lumo_spin1_idx]
            lumo_spin2 = result_dict['eigen_spin2_au'][lumo_spin2_idx]
            result_dict['bandgap_spin1_au'] = lumo_spin1 - homo_spin1
            result_dict['bandgap_spin2_au'] = lumo_spin2 - homo_spin2

        if "kpoint_data" in result_dict:
            bnds = BandsData()
            bnds.set_kpoints(result_dict["kpoint_data"]["kpoints"])
            bnds.labels = result_dict["kpoint_data"]["labels"]
            bnds.set_bands(
                result_dict["kpoint_data"]["bands"],
                units=result_dict["kpoint_data"]["bands_unit"],
            )
            self.out("output_bands", bnds)
            del result_dict["kpoint_data"]

        self.out("output_parameters", Dict(dict=result_dict))
        return None
Ejemplo n.º 4
0
def bands_to_bandsdata(bands_info, kpoints, bands):
    """
    Convert the result of parser_dot_bands into a BandsData object

    :param bands_info: A dictionary of the informations of the bands file.
      contains field such as eferemi, units, cell
    :param kpoints: An array of the kpoints of the bands, rows are
      (kindex, kx, ky, kz, weight)
    :param bands: The actual bands array
    :return: A BandsData object
    :rtype: ``aiida.orm.bands.data.array.bands.BandsData``
    """

    bands_node = BandsData()

    # Extract the index of the kpoints
    kpn_array = np.asarray(kpoints)
    k_index = kpn_array[:, 0]

    # We need to restore the order of the kpoints
    k_sort = np.argsort(k_index)
    # Sort the kpn_array
    kpn_array = kpn_array[k_sort]

    _weights = kpn_array[:, -1]
    kpts = kpn_array[:, 1:-1]
    bands_node.set_kpoints(kpts, weights=_weights)

    # Sort the bands to match the order of the kpoints
    bands_array = np.asarray(bands)[k_sort]
    # We need to swap the axes from kpt,spin,engs to spin,kpt,engs
    bands_array = bands_array.swapaxes(0, 1)

    # Squeeze the first dimension e.g when there is a single spin
    if bands_array.shape[0] == 1:
        bands_array = bands_array[0]
    bands_array = bands_array * units['Eh']
    bands_info = dict(bands_info)  # Create a copy
    # Convert the units for the fermi energies
    if isinstance(bands_info['efermi'], list):
        bands_info['efermi'] = [x * units['Eh'] for x in bands_info['efermi']]
    else:
        bands_info['efermi'] = bands_info['efermi'] * units['Eh']

    bands_node.set_bands(bands_array, units="eV")
    # PBC is always true as this is PW DFT....
    bands_node.set_cell(bands_info['cell'], pbc=(True, True, True))

    # Store information from *.bands in the attributes
    # This is needs as we need to know the number of electrons
    # and the fermi energy
    for key, value in bands_info.items():
        bands_node.set_attribute(key, value)
    return bands_node
Ejemplo n.º 5
0
    def _parse_stdout(self, out_folder):
        """Advanced CP2K output file parser"""

        from aiida.orm import BandsData
        from .parser_functions import parse_cp2k_output_advanced

        # pylint: disable=protected-access

        fname = self.node.process_class._DEFAULT_OUTPUT_FILE
        if fname not in out_folder._repository.list_object_names():
            raise OutputParsingError("Cp2k output file not retrieved")

        abs_fn = os.path.join(
            out_folder._repository._get_base_folder().abspath, fname)
        with io.open(abs_fn, mode="r", encoding="utf-8") as fobj:
            result_dict = parse_cp2k_output_advanced(fobj)

        # nwarnings is the last thing to be printed in th eCP2K output file:
        # if it is not there, CP2K didn't finish properly
        if 'nwarnings' not in result_dict:
            raise OutputParsingError("CP2K did not finish properly.")

        # Compute the bandgap for Spin1 and Spin2 if eigen was parsed (works also with smearing!)
        if 'eigen_spin1_au' in result_dict:
            if result_dict['dft_type'] == "RKS":
                result_dict['eigen_spin2_au'] = result_dict['eigen_spin1_au']

            lumo_spin1_idx = result_dict['init_nel_spin1']
            lumo_spin2_idx = result_dict['init_nel_spin2']
            if (lumo_spin1_idx > len(result_dict['eigen_spin1_au'])-1) or \
               (lumo_spin2_idx > len(result_dict['eigen_spin2_au'])-1):
                #electrons jumped from spin1 to spin2 (or opposite): assume last eigen is lumo
                lumo_spin1_idx = len(result_dict['eigen_spin1_au']) - 1
                lumo_spin2_idx = len(result_dict['eigen_spin2_au']) - 1
            homo_spin1 = result_dict['eigen_spin1_au'][lumo_spin1_idx - 1]
            homo_spin2 = result_dict['eigen_spin2_au'][lumo_spin2_idx - 1]
            lumo_spin1 = result_dict['eigen_spin1_au'][lumo_spin1_idx]
            lumo_spin2 = result_dict['eigen_spin2_au'][lumo_spin2_idx]
            result_dict['bandgap_spin1_au'] = lumo_spin1 - homo_spin1
            result_dict['bandgap_spin2_au'] = lumo_spin2 - homo_spin2

        if "kpoint_data" in result_dict:
            bnds = BandsData()
            bnds.set_kpoints(result_dict["kpoint_data"]["kpoints"])
            bnds.labels = result_dict["kpoint_data"]["labels"]
            bnds.set_bands(
                result_dict["kpoint_data"]["bands"],
                units=result_dict["kpoint_data"]["bands_unit"],
            )
            self.out("output_bands", bnds)
            del result_dict["kpoint_data"]

        self.out("output_parameters", Dict(dict=result_dict))
Ejemplo n.º 6
0
def bands_from_castepbin(seedname, fmanager):
    """
    Acquire and prepare bands data from the castep_bin file instead
    """

    with fmanager.open(seedname + '.castep_bin', 'rb') as handle:
        binfile = CastepbinFile(fileobj=handle)

    bands_node = BandsData()
    kidx = binfile.kpoints_indices
    sort_idx = np.argsort(kidx)
    # Generated sorted arrays
    kpoints = binfile.kpoints[sort_idx, :]
    weights = binfile.kpoint_weights[sort_idx].astype(float)
    eigenvalues = binfile.eigenvalues[:, sort_idx, :]
    occupancies = binfile.occupancies[:, sort_idx, :]
    efermi = binfile.fermi_energy

    bands_node.set_kpoints(kpoints, weights=weights)
    bands_node.set_bands(eigenvalues, occupations=occupancies, units="eV")
    bands_node.set_cell(binfile.cell, pbc=(True, True, True))
    bands_node.set_attribute('efermi', efermi)

    return bands_node
Ejemplo n.º 7
0
def spin_dependent_subparser(out_info_dict):
    """This find the projection and bands arrays from the out_file and out_info_dict. Used to handle the different
    possible spin-cases in a convenient manner.

    :param out_info_dict: contains various technical internals useful in parsing
    :return: ProjectionData, BandsData parsed from out_file
    """

    out_file = out_info_dict['out_file']
    spin_down = out_info_dict['spin_down']
    od = out_info_dict  #using a shorter name for convenience
    #   regular expressions needed for later parsing
    WaveFraction1_re = re.compile(r'\=(.*?)\*')  # state composition 1
    WaveFractionremain_re = re.compile(r'\+(.*?)\*')  # state comp 2
    FunctionId_re = re.compile(r'\#(.*?)\]')  # state identity
    # primes arrays for the later parsing
    num_wfc = len(od['wfc_lines'])
    bands = np.zeros([od['k_states'], od['num_bands']])
    projection_arrays = np.zeros([od['k_states'], od['num_bands'], num_wfc])

    try:
        for i in range(od['k_states']):
            if spin_down:
                i += od['k_states']
            # grabs band energy
            for j in range(i * od['num_bands'], (i + 1) * od['num_bands'], 1):
                out_ind = od['e_lines'][j]
                try:
                    # post ~6.3 output format "e ="
                    val = out_file[out_ind].split()[2]
                    float(val)
                except ValueError:
                    # pre ~6.3 output format? "==== e("
                    val = out_file[out_ind].split()[4]
                bands[i % od['k_states']][j % od['num_bands']] = val
                #subloop grabs pdos
                wave_fraction = []
                wave_id = []
                for k in range(od['e_lines'][j] + 1, od['psi_lines'][j], 1):
                    out_line = out_file[k]
                    wave_fraction += WaveFraction1_re.findall(out_line)
                    wave_fraction += WaveFractionremain_re.findall(out_line)
                    wave_id += FunctionId_re.findall(out_line)
                if len(wave_id) != len(wave_fraction):
                    raise IndexError
                for l in range(len(wave_id)):
                    wave_id[l] = int(wave_id[l])
                    wave_fraction[l] = float(wave_fraction[l])
                    #sets relevant values in pdos_array
                    projection_arrays[i % od['k_states']][j % od['num_bands']][
                        wave_id[l] - 1] = wave_fraction[l]
    except IndexError:
        raise QEOutputParsingError(
            'the standard out file does not comply with the official documentation.'
        )

    bands_data = BandsData()
    # Attempts to retrieve the kpoints from the parent calc
    parent_calc = out_info_dict['parent_calc']
    try:
        parent_kpoints = parent_calc.get_incoming(
            link_label_filter='kpoints').one().node
    except ValueError:
        raise QEOutputParsingError(
            'The parent had no input kpoints! Cannot parse from this!')
    try:
        if len(od['k_vect']) != len(parent_kpoints.get_kpoints()):
            raise AttributeError
        bands_data.set_kpointsdata(parent_kpoints)
    except AttributeError:
        bands_data.set_kpoints(od['k_vect'].astype(float))

    bands_data.set_bands(bands, units='eV')

    orbitals = out_info_dict['orbitals']
    if len(orbitals) != np.shape(projection_arrays[0, 0, :])[0]:
        raise QEOutputParsingError('There was an internal parsing error, '
                                   ' the projection array shape does not agree'
                                   ' with the number of orbitals')
    projection_data = ProjectionData()
    projection_data.set_reference_bandsdata(bands_data)
    projections = [projection_arrays[:, :, i] for i in range(len(orbitals))]

    # Do the bands_check manually here
    for projection in projections:
        if np.shape(projection) != np.shape(bands):
            raise AttributeError('Projections not the same shape as the bands')

    #insert here some logic to assign pdos to the orbitals
    pdos_arrays = spin_dependent_pdos_subparser(out_info_dict)
    energy_arrays = [out_info_dict['energy']] * len(orbitals)
    projection_data.set_projectiondata(orbitals,
                                       list_of_projections=projections,
                                       list_of_energy=energy_arrays,
                                       list_of_pdos=pdos_arrays,
                                       bands_check=False)
    # pdos=pdos_arrays
    return bands_data, projection_data
Ejemplo n.º 8
0
 def _aiida_bands_data(self, data, cell, kpoints_dict):
     if not data:
         return False
     kpt_idx = sorted(data.keys())  #  list of kpoint indices
     try:
         k_list = [kpoints_dict[i]
                   for i in kpt_idx]  # list of k-point triplet
     except KeyError:
         # kpoint triplets are not present (true  for .qp and so on, can not use BandsData)
         # We use the internal Yambo Format  [ [Eo_1, Eo_2,... ], ...[So_1,So_2,] ]
         #                                  QP_TABLE  [[ib_1,ik_1,isp_1]      ,[ib_n,ik_n,isp_n]]
         # Each entry in DATA has corresponding legend in QP_TABLE that defines its details
         # like   ib= Band index,  ik= kpoint index,  isp= spin polarization index.
         #  Eo_1 =>  at ib_1, ik_1 isp_1.
         pdata = ArrayData()
         QP_TABLE = []
         ORD = []
         Eo = []
         E_minus_Eo = []
         So = []
         Z = []
         for ky in data.keys():  # kp == kpoint index as a string  1,2,..
             for ind in range(len(data[ky]['Band'])):
                 try:
                     Eo.append(data[ky]['Eo'][ind])
                 except KeyError:
                     pass
                 try:
                     E_minus_Eo.append(data[ky]['E-Eo'][ind])
                 except KeyError:
                     pass
                 try:
                     So.append(data[ky]['Sc|Eo'][ind])
                 except KeyError:
                     pass
                 try:
                     Z.append(data[ky]['Z'][ind])
                 except KeyError:
                     pass
                 ik = int(ky)
                 ib = data[ky]['Band'][ind]
                 isp = 0
                 if 'Spin_Pol' in list(data[ky].keys()):
                     isp = data[ky]['Spin_Pol'][ind]
                 QP_TABLE.append([ik, ib, isp])
         pdata.set_array('Eo', numpy.array(Eo))
         pdata.set_array('E_minus_Eo', numpy.array(E_minus_Eo))
         pdata.set_array('So', numpy.array(So))
         pdata.set_array('Z', numpy.array(Z))
         pdata.set_array('qp_table', numpy.array(QP_TABLE))
         return pdata
     quasiparticle_bands = BandsData()
     quasiparticle_bands.set_cell(cell)
     quasiparticle_bands.set_kpoints(k_list, cartesian=True)
     # labels will come from any of the keys in the nested  kp_point data,
     # there is a uniform set of observables for each k-point, ie Band, Eo, ...
     # ***FIXME BUG does not seem to handle spin polarizes at all when constructing bandsdata***
     bands_labels = [
         legend for legend in sorted(data[list(data.keys())[0]].keys())
     ]
     append_list = [[] for i in bands_labels]
     for kp in kpt_idx:
         for i in range(len(bands_labels)):
             append_list[i].append(data[kp][bands_labels[i]])
     generalised_bands = [numpy.array(it) for it in append_list]
     quasiparticle_bands.set_bands(bands=generalised_bands,
                                   units='eV',
                                   labels=bands_labels)
     return quasiparticle_bands
Ejemplo n.º 9
0
    def _get_output_nodes(self, output_path, messages_path, xml_path,
                          json_path, bands_path):
        """
        Extracts output nodes from the standard output and standard error
        files. (And XML and JSON files)
        """
        from aiida.orm import TrajectoryData
        import re

        parser_version = '1.0.1'
        parser_info = {}
        parser_info['parser_info'] = 'AiiDA Siesta Parser V. {}'.format(
            parser_version)
        parser_info['parser_warnings'] = []

        #No need for checks anymore

        xmldoc = get_parsed_xml_doc(xml_path)

        in_struc = self.node.inputs.structure

        try:
            in_settings = self.node.inputs.settings
        except exceptions.NotExistent:
            in_settings = None

        result_dict = get_dict_from_xml_doc(xmldoc)

        # Add timing information
        #if json_path is None:
        ###TODO###
        #Not sure how to implement what once was logger.info
        #Also not sure I understood the purpose of this file
        if json_path is not None:
            from .json_time import get_timing_info
            global_time, timing_decomp = get_timing_info(json_path)
            if global_time is None:
                raise OutputParsingError(
                    "Cannot fully parse the time.json file")
            else:
                result_dict["global_time"] = global_time
                result_dict["timing_decomposition"] = timing_decomp

        # Add warnings
        if messages_path is None:
            # Perhaps using an old version of Siesta
            warnings_list = ['WARNING: No MESSAGES file...']
        else:
            successful, warnings_list = self.get_warnings_from_file(
                messages_path)

        ###TODO### or maybe not
        #How do we process this successfull booelan?

        result_dict["warnings"] = warnings_list

        # Add parser info dictionary
        parsed_dict = dict(
            list(result_dict.items()) + list(parser_info.items()))

        output_data = Dict(dict=parsed_dict)

        self.out('output_parameters', output_data)

        # If the structure has changed, save it
        if is_variable_geometry(xmldoc):
            # Get the input structure to copy its site names,
            # as the CML file traditionally contained only the
            # atomic symbols.
            #
            struc = get_last_structure(xmldoc, in_struc)
            # result_list.append((self.get_linkname_outstructure(),struc))
            self.out(self.get_linkname_outstructure(), struc)

        # Save forces and stress in an ArrayData object
        forces, stress = get_final_forces_and_stress(xmldoc)

        if forces is not None and stress is not None:
            # from aiida.orm.nodes.array import ArrayData
            from aiida.orm import ArrayData
            arraydata = ArrayData()
            arraydata.set_array('forces', np.array(forces))
            arraydata.set_array('stress', np.array(stress))
            # result_list.append((self.get_linkname_fs_and_stress(),arraydata))
            self.out(self.get_linkname_fs_and_stress(), arraydata)

        # Parse band-structure information if available
        if bands_path is not None:
            bands, coords = self.get_bands(bands_path)
            from aiida.orm import BandsData
            arraybands = BandsData()
            f = self.node.inputs.bandskpoints  #Temporary workaround due to a bug
            #f._set_reciprocal_cell()         #in KpointData (issue #2749)
            arraybands.set_kpoints(f.get_kpoints(cartesian=True))
            arraybands.labels = f.labels
            arraybands.set_bands(bands, units="eV")
            self.out(self.get_linkname_bands(), arraybands)
            bandsparameters = Dict(dict={"kp_coordinates": coords})
            self.out(self.get_linkname_bandsparameters(), bandsparameters)

        return result_dict
Ejemplo n.º 10
0
    def _parse_gsr(self):
        """Abinit GSR parser."""
        # Output GSR Abinit NetCDF file - Default name is aiidao_GSR.nc
        fname = f'{self.node.get_attribute("prefix")}o_GSR.nc'
        # Absolute path of the folder in which aiidao_GSR.nc is stored
        path = self.node.get_remote_workdir()

        if fname not in self.retrieved.list_object_names():
            return self.exit_codes.ERROR_MISSING_OUTPUT_FILES

        with abilab.abiopen(path + '/' + fname) as gsr:
            gsr_data = {
                'abinit_version':
                gsr.abinit_version,
                'cart_stress_tensor':
                gsr.cart_stress_tensor.tolist(),
                'cart_stress_tensor' + UNITS_SUFFIX:
                DEFAULT_STRESS_UNITS,
                'is_scf_run':
                bool(gsr.is_scf_run),
                # 'cart_forces': gsr.cart_forces.tolist(),
                # 'cart_forces' + units_suffix: DEFAULT_FORCE_UNITS,
                'forces':
                gsr.cart_forces.tolist(),  # backwards compatibility
                'forces' + UNITS_SUFFIX:
                DEFAULT_FORCE_UNITS,
                'energy':
                float(gsr.energy),
                'energy' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_localpsp':
                float(gsr.energy_terms.e_localpsp),
                'e_localpsp' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_eigenvalues':
                float(gsr.energy_terms.e_eigenvalues),
                'e_eigenvalues' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_ewald':
                float(gsr.energy_terms.e_ewald),
                'e_ewald' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_hartree':
                float(gsr.energy_terms.e_hartree),
                'e_hartree' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_corepsp':
                float(gsr.energy_terms.e_corepsp),
                'e_corepsp' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_corepspdc':
                float(gsr.energy_terms.e_corepspdc),
                'e_corepspdc' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_kinetic':
                float(gsr.energy_terms.e_kinetic),
                'e_kinetic' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_nonlocalpsp':
                float(gsr.energy_terms.e_nonlocalpsp),
                'e_nonlocalpsp' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_entropy':
                float(gsr.energy_terms.e_entropy),
                'e_entropy' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'entropy':
                float(gsr.energy_terms.entropy),
                'entropy' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_xc':
                float(gsr.energy_terms.e_xc),
                'e_xc' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_xcdc':
                float(gsr.energy_terms.e_xcdc),
                'e_xcdc' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_paw':
                float(gsr.energy_terms.e_paw),
                'e_paw' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_pawdc':
                float(gsr.energy_terms.e_pawdc),
                'e_pawdc' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_elecfield':
                float(gsr.energy_terms.e_elecfield),
                'e_elecfield' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_magfield':
                float(gsr.energy_terms.e_magfield),
                'e_magfield' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_fermie':
                float(gsr.energy_terms.e_fermie),
                'e_fermie' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_sicdc':
                float(gsr.energy_terms.e_sicdc),
                'e_sicdc' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_exactX':
                float(gsr.energy_terms.e_exactX),
                'e_exactX' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'h0':
                float(gsr.energy_terms.h0),
                'h0' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_electronpositron':
                float(gsr.energy_terms.e_electronpositron),
                'e_electronpositron' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'edc_electronpositron':
                float(gsr.energy_terms.edc_electronpositron),
                'edc_electronpositron' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e0_electronpositron':
                float(gsr.energy_terms.e0_electronpositron),
                'e0_electronpositron' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'e_monopole':
                float(gsr.energy_terms.e_monopole),
                'e_monopole' + UNITS_SUFFIX:
                DEFAULT_ENERGY_UNITS,
                'pressure':
                float(gsr.pressure),
                'pressure' + UNITS_SUFFIX:
                DEFAULT_STRESS_UNITS
            }

            try:
                # will return an integer 0 if non-magnetic calculation is run; convert it to a float
                total_magnetization = float(gsr.ebands.get_collinear_mag())
                gsr_data['total_magnetization'] = total_magnetization
                gsr_data['total_magnetization' +
                         UNITS_SUFFIX] = DEFAULT_MAGNETIZATION_UNITS
            except ValueError as valerr:
                # get_collinear_mag will raise ValueError if it doesn't know what to do
                if 'Cannot calculate collinear magnetization' in valerr.args[
                        0]:
                    pass
                else:
                    raise valerr

            try:
                bands_data = BandsData()
                bands_data.set_kpoints(gsr.ebands.kpoints.get_cart_coords())
                bands_data.set_bands(np.array(gsr.ebands.eigens),
                                     units=str(gsr.ebands.eigens.unit))
                self.out('output_bands', bands_data)
            except:  # pylint: disable=bare-except
                pass

        self.out('output_parameters', Dict(dict=gsr_data))