Exemple #1
0
def parse_dosfiles(dosfolder):
    """
    parse dos files to XyData nodes
    """
    from masci_tools.io.common_functions import interpolate_dos
    from masci_tools.io.common_functions import get_Ry2eV

    eVscale = get_Ry2eV()

    ef, dos, dos_int = interpolate_dos(dosfolder, return_original=True)

    # convert to eV units
    dos[:, :, 0] = (dos[:, :, 0] - ef) * eVscale
    dos[:, :, 1:] = dos[:, :, 1:] / eVscale
    dos_int[:, :, 0] = (dos_int[:, :, 0] - ef) * eVscale
    dos_int[:, :, 1:] = dos_int[:, :, 1:] / eVscale

    # create output nodes
    dosnode = XyData()
    dosnode.set_x(dos[:, :, 0], 'E-EF', 'eV')
    name = ['tot', 's', 'p', 'd', 'f', 'g']
    name = name[:len(dos[0, 0, 1:]) - 1] + ['ns']
    ylists = [[], [], []]
    for l in range(len(name)):
        ylists[0].append(dos[:, :, 1 + l])
        ylists[1].append('dos ' + name[l])
        ylists[2].append('states/eV')
    dosnode.set_y(ylists[0], ylists[1], ylists[2])
    dosnode.label = 'dos_data'
    dosnode.description = 'Array data containing uniterpolated DOS (i.e. dos at finite imaginary part of energy). 3D array with (atoms, energy point, l-channel) dimensions.'

    # now create XyData node for interpolated data
    dosnode2 = XyData()
    dosnode2.set_x(dos_int[:, :, 0], 'E-EF', 'eV')
    ylists = [[], [], []]
    for l in range(len(name)):
        ylists[0].append(dos_int[:, :, 1 + l])
        ylists[1].append('interpolated dos ' + name[l])
        ylists[2].append('states/eV')
    dosnode2.set_y(ylists[0], ylists[1], ylists[2])
    dosnode2.label = 'dos_interpol_data'
    dosnode2.description = 'Array data containing interpolated DOS (i.e. dos at real axis). 3D array with (atoms, energy point, l-channel) dimensions.'

    return dosnode, dosnode2
Exemple #2
0
    def check_dos(self):
        """
        checks if dos of starting potential is ok
        """
        dos_ok = True
        self.ctx.dos_check_fail_reason = None

        if self.ctx.check_dos:
            # check parser output
            doscal = self.ctx.doscal
            try:
                dos_outdict = doscal.outputs.results_wf.get_dict()
                if not dos_outdict['successful']:
                    self.report("ERROR: DOS workflow unsuccessful")
                    self.ctx.doscheck_ok = False
                    return self.exit_codes.ERROR_DOSRUN_FAILED

                if dos_outdict['list_of_errors'] != []:
                    self.report(
                        "ERROR: DOS wf output contains errors: {}".format(
                            dos_outdict['list_of_errors']))
                    self.ctx.doscheck_ok = False
                    return self.exit_codes.ERROR_DOSRUN_FAILED
            except:
                self.ctx.doscheck_ok = False
                return self.exit_codes.ERROR_DOSRUN_FAILED

            # needed for checks
            emin = self.ctx.voro_calc.res.emin

            # check for negative DOS
            try:
                dosdata = doscal.outputs.dos_data
                natom = len(self.ctx.voro_calc.res.shapes)
                nspin = dos_outdict['nspin']

                ener = dosdata.get_x()[1]  # shape= natom*nspin, nept
                totdos = dosdata.get_y()[0][1]  # shape= natom*nspin, nept

                if len(ener) != nspin * natom:
                    self.report(
                        "ERROR: DOS output shape does not fit nspin, natom information: len(energies)={}, natom={}, nspin={}"
                        .format(len(ener), natom, nspin))
                    self.ctx.doscheck_ok = False
                    return self.exit_codes.ERROR_DOSRUN_FAILED

                # deal with snpin==1 or 2 cases and check negtive DOS
                for iatom in range(natom // nspin):
                    for ispin in range(nspin):
                        x, y = ener[iatom * nspin +
                                    ispin], totdos[iatom * nspin + ispin]
                        if nspin == 2 and ispin == 0:
                            y = -y
                        if y.min() < 0:
                            self.report(
                                "INFO: negative DOS value found in (atom, spin)=({},{}) at iteration {}"
                                .format(iatom, ispin, self.ctx.iter))
                            dos_ok = False
                            self.ctx.dos_check_fail_reason = 'DOS negative'

                # check starting EMIN
                dosdata_interpol = doscal.outputs.dos_data_interpol

                ener = dosdata_interpol.get_x()[1]  # shape= natom*nspin, nept
                totdos = dosdata_interpol.get_y()[0][
                    1]  # shape= natom*nspin, nept [0] for total DOS
                Ry2eV = get_Ry2eV()

                for iatom in range(natom // nspin):
                    for ispin in range(nspin):
                        x, y = ener[iatom * nspin +
                                    ispin], totdos[iatom * nspin + ispin]
                        xrel = abs(x - (emin - self.ctx.efermi) * Ry2eV)
                        mask_emin = where(xrel == xrel.min())
                        ymin = abs(y[mask_emin])
                        if ymin > self.ctx.threshold_dos_zero:
                            self.report(
                                "INFO: DOS at emin not zero! {}>{}".format(
                                    ymin, self.ctx.threshold_dos_zero))
                            dos_ok = False
                            self.ctx.dos_check_fail_reason = 'EMIN too high'
            except AttributeError:
                dos_ok = False

            # check for position of core states
            ecore_all = self.ctx.voro_calc.res.core_states_group.get(
                'energy_highest_lying_core_state_per_atom')
            ecore_max = max(ecore_all)
            self.report("INFO: emin= {} Ry".format(emin))
            self.report("INFO: highest core state= {} Ry".format(ecore_max))
            if ecore_max is not None:
                if ecore_max >= emin:
                    error = "ERROR: contour contains core states!!!"
                    self.report(error)
                    dos_ok = False
                    self.ctx.dos_check_fail_reason = 'core state in contour'
                    # TODO maybe some logic to automatically deal with this issue?
                    # for now stop if this case occurs
                    return self.exit_codes.ERROR_CORE_STATES_IN_CONTOUR
                elif abs(ecore_max - emin) < self.ctx.min_dist_core_states:
                    error = "ERROR: core states too close to energy contour start!!!"
                    self.report(error)
                    dos_ok = False
                    self.ctx.dos_check_fail_reason = 'core state too close'
                else:
                    self.report('INFO: DOS check successful')

            #TODO check for semi-core-states

            #TODO check rest of dos_output node if something seems important to check

        # finally set the value in context (needed in do_iteration_check)
        if dos_ok:
            self.ctx.doscheck_ok = True
        else:
            self.ctx.doscheck_ok = False
Exemple #3
0
    def check_voronoi(self):
        """
        check voronoi output. return True/False if voronoi output is ok/problematic
        if output is problematic try to increase some parameters (e.g. cluster radius) and rerun up tp N_rerun_max times
        initializes with returning True
        """

        #do some checks with the voronoi output (finally sets self.ctx.voro_ok)
        self.ctx.voro_ok = True

        # check calculation state (calculation must be completed)
        if not self.ctx.voro_calc.is_finished_ok:
            self.report("ERROR: Voronoi calculation not in FINISHED state")
            self.ctx.voro_ok = False
            return self.exit_codes.ERROR_VORONOI_FAILED

        # check if parser returned some error
        voro_parser_errors = self.ctx.voro_calc.res.parser_errors
        if voro_parser_errors != []:
            self.report("ERROR: Voronoi Parser returned Error(s): {}".format(
                voro_parser_errors))
            self.ctx.voro_ok = False
            return self.exit_codes.ERROR_VORONOI_PARSING_FAILED

        # check self.ctx.nclsmin condition
        clsinfo = self.ctx.voro_calc.res.cluster_info_group
        ncls = clsinfo.pop('number_of_clusters')

        nclsmin_last_calc = 1000
        for icls in range(len(clsinfo['cluster_info_atoms'])):
            tmp_ncls = clsinfo['cluster_info_atoms'][icls]['sites']
            if tmp_ncls < nclsmin_last_calc:
                nclsmin_last_calc = tmp_ncls
        self.report("INFO: number of atoms in smallest cluster: {}".format(
            nclsmin_last_calc))

        if self.ctx.nclsmin > nclsmin_last_calc or ncls < 1:
            self.report(
                "WARNING: minimal cluster smaller than threshold of {}".format(
                    self.ctx.nclsmin))
            self.ctx.voro_ok = False

        # check radii condition
        radii = self.ctx.voro_calc.res.radii_atoms_group
        r_ratio1 = radii[0]['rout_over_dist_nn']
        r_ratio2 = radii[0]['rmt0_over_rout']
        if r_ratio1 >= 100. or r_ratio2 >= 100.:
            self.report(
                "ERROR: radii information inconsistent: Rout/dis_NN={}, RMT0/Rout={}"
                .format(r_ratio1, r_ratio2))
            self.ctx.voro_ok = False
            return self.exit_codes.ERROR_VORONOI_INVALID_RADII

        # fix emin/emax
        # remember: efermi, emin and emax are in internal units (Ry) but delta_e is in eV!
        eV2Ry = 1. / get_Ry2eV()
        emin_dos = self.ctx.dos_params_dict['emin']
        emin_out = self.ctx.voro_calc.res.emin
        self.report("INFO: emin dos input: {}, emin voronoi output: {}".format(
            emin_dos, emin_out))
        if emin_out - self.ctx.delta_e * eV2Ry < emin_dos:
            self.ctx.dos_params_dict[
                'emin'] = emin_out - self.ctx.delta_e * eV2Ry
            self.report(
                "INFO: emin ({} Ry) - delta_e ({} Ry) smaller than emin ({} Ry) of dos input. Setting automatically to {} Ry"
                .format(emin_out, self.ctx.delta_e * eV2Ry, emin_dos,
                        emin_out - self.ctx.delta_e * eV2Ry))

        ret = self.ctx.voro_calc.outputs.retrieved
        if 'potential_overwrite' in self.ctx.voro_calc.inputs:
            potfile_overwrite = self.ctx.voro_calc.inputs.potential_overwrite
            with potfile_overwrite.open(potfile_overwrite.filename) as f:
                potfile_path = f.name
        else:
            with ret.open(VoronoiCalculation._OUT_POTENTIAL_voronoi) as f:
                potfile_path = f.name
        self.ctx.efermi = get_ef_from_potfile(potfile_path)
        emax = self.ctx.dos_params_dict['emax']
        self.report(
            "INFO: emax dos input: {}, efermi voronoi output: {}".format(
                emax, self.ctx.efermi))
        if emax < self.ctx.efermi + self.ctx.delta_e * eV2Ry:
            self.ctx.dos_params_dict[
                'emax'] = self.ctx.efermi + self.ctx.delta_e * eV2Ry
            self.report(
                "INFO: self.ctx.efermi ({} Ry) + delta_e ({} Ry) larger than emax ({} Ry). Setting automatically to {} Ry"
                .format(self.ctx.efermi, self.ctx.delta_e * eV2Ry, emax,
                        self.ctx.efermi + self.ctx.delta_e * eV2Ry))

        #TODO implement other checks?

        self.report("INFO: Voronoi check finished with result: {}".format(
            self.ctx.voro_ok))

        # finally return result of check
        return self.ctx.voro_ok
Exemple #4
0
    def run_voronoi(self):
        """
        run voronoi calculation with parameters from input
        """
        # incerement iteration counter
        self.ctx.iter += 1

        # increase some parameters
        if self.ctx.iter > 1:
            # check if cluster size is actually the reason for failure
            if self.ctx.dos_check_fail_reason not in [
                    'EMIN too high', 'core state in contour',
                    'core state too close'
            ]:
                self.ctx.r_cls = self.ctx.r_cls * self.ctx.fac_clsincrease

        structure = self.inputs.structure
        self.ctx.formula = structure.get_formula()
        label = 'voronoi calculation step {}'.format(self.ctx.iter)
        description = '{} vornoi on {}'.format(self.ctx.description_wf,
                                               self.ctx.formula)

        voronoicode = self.inputs.voronoi

        # get valid KKR parameters
        if self.ctx.iter > 1:
            # take value from last run to continue
            params = self.ctx.last_params
            first_iter = False
        else:
            # used input or defaults in first iteration
            first_iter = True
            if 'calc_parameters' in self.inputs:
                params = self.inputs.calc_parameters
            else:
                kkrparams_default = kkrparams()
                para_version = self._kkr_default_params[1]
                for key, val in self._kkr_default_params[0].items():
                    kkrparams_default.set_value(key, val, silent=True)
                # create Dict node
                params = Dict(dict=kkrparams_default.get_dict())
                params.label = 'Defaults for KKR parameter node'
                params.description = 'defaults as defined in kkrparams of version {}'.format(
                    para_version)
            #  set last_params accordingly (used below for provenance tracking)
            self.ctx.last_params = params

        self.report("INFO: input params: {}".format(params.get_dict()))

        # check if RCLUSTZ is set and use setting from wf_parameters instead (calls update_params_wf to keep track of provenance)
        updated_params = False
        update_list = []
        kkr_para = kkrparams()
        for key, val in params.get_dict().items():
            kkr_para.set_value(key, val, silent=True)
        set_vals = kkr_para.get_set_values()
        set_vals = [keyvalpair[0] for keyvalpair in set_vals]
        default_values = kkrparams.get_KKRcalc_parameter_defaults()[0]
        if 'RCLUSTZ' in set_vals:
            rcls_input = params.get_dict()['RCLUSTZ']
            # set r_cls by default or from input in first iteration
            if self.ctx.r_cls < rcls_input and first_iter:
                self.ctx.r_cls = rcls_input
                updated_params = True
                update_list.append('RCLUSTZ')
            elif self.ctx.r_cls > rcls_input:
                # change rcls with iterations
                updated_params = True
                update_list.append('RCLUSTZ')
        else:
            updated_params = True
            update_list.append('RCLUSTZ')
        # in case of dos check verify that RMAX, GMAX are set and use setting from wf_parameters otherwise
        if 'RMAX' in set_vals:
            update_list.append('RMAX')
            rmax_input = params.get_dict()['RMAX']
        elif self.ctx.check_dos:  # add only if doscheck is done
            updated_params = True
            update_list.append('RMAX')
            rmax_input = kkrparams.default_values.get('RMAX')
        if 'GMAX' in set_vals:
            update_list.append('GMAX')
            gmax_input = params.get_dict()['GMAX']
        elif self.ctx.check_dos:  # add only if doscheck is done
            updated_params = True
            update_list.append('GMAX')
            gmax_input = kkrparams.default_values.get('GMAX')
        # check if any mandatory keys are not set and set them with the default values if missing in input parameters
        for key, value in default_values.items():
            if key not in update_list and key not in set_vals:
                self.report("INFO: setting {} to default value {}".format(
                    key, value))
                kkr_para.set_value(key, value)

        # check if Fermi lavel should be set with input value
        if self.ctx.ef_set is not None:
            update_list.append('ef_set')

        # check if emin should be changed:
        skip_voro = False
        if self.ctx.iter > 1:
            if (self.ctx.dos_check_fail_reason == 'EMIN too high' or
                    self.ctx.dos_check_fail_reason == 'core state too close'):
                # decrease emin  by self.ctx.delta_e
                emin_old = self.ctx.dos_params_dict['emin']
                eV2Ry = 1. / get_Ry2eV()
                emin_new = emin_old - self.ctx.delta_e * eV2Ry
                self.ctx.dos_params_dict['emin'] = emin_new
                updated_params = True
                update_list.append('EMIN')
                skip_voro = True

        # store updated nodes (also used via last_params in kkr_scf_wc)
        if updated_params:
            # set values that are updated
            if 'RCLUSTZ' in update_list:
                kkr_para.set_value('RCLUSTZ', self.ctx.r_cls)
                self.report("INFO: setting RCLUSTZ to {}".format(
                    self.ctx.r_cls))
            if 'EMIN' in update_list:
                kkr_para.set_value('EMIN', emin_new)
                self.report("INFO: setting EMIN to {}".format(emin_new))
            if 'RMAX' in update_list:
                kkr_para.set_value('RMAX', rmax_input)
                self.report(
                    "INFO: setting RMAX to {} (needed for DOS check with KKRcode)"
                    .format(rmax_input))
            if 'GMAX' in update_list:
                kkr_para.set_value('GMAX', gmax_input)
                self.report(
                    "INFO: setting GMAX to {} (needed for DOS check with KKRcode)"
                    .format(gmax_input))
            if 'ef_set' in update_list:
                kkr_para.set_value('EFSET', self.ctx.ef_set)
                self.report(
                    "INFO: setting Fermi level of stating potential to {}".
                    format(self.ctx.ef_set))

            updatenode = Dict(dict=kkr_para.get_dict())
            updatenode.description = 'changed values: {}'.format(update_list)
            if first_iter:
                updatenode.label = 'initial params from wf input'
                # used workfunction for provenance tracking if parameters have been changed
                params = update_params_wf(self.ctx.last_params, updatenode)
                self.ctx.last_params = params
            else:
                updatenode.label = 'updated params: {}'.format(update_list)
                # also keep track of last voronoi output if that has been used
                voro_out = self.ctx.voro_calc.outputs.output_parameters
                params = update_voro_input(self.ctx.last_params, updatenode,
                                           voro_out)
                self.ctx.last_params = params

        # run voronoi step
        if not skip_voro:
            options = {
                'queue_name': self.ctx.queue,
                'resources': self.ctx.resources,
                'max_wallclock_seconds': self.ctx.max_wallclock_seconds,
                'custom_scheduler_commands': self.ctx.custom_scheduler_commands
            }

            builder = get_inputs_voronoi(voronoicode,
                                         structure,
                                         options,
                                         label,
                                         description,
                                         params=params)
            if 'startpot_overwrite' in self.inputs:
                builder.potential_overwrite = self.inputs.startpot_overwrite
            self.report('INFO: run voronoi step {}'.format(self.ctx.iter))
            future = self.submit(builder)

            # return remote_voro (passed to dos calculation as input)
            return ToContext(voro_calc=future)
        else:
            self.report(
                "INFO: skipping voronoi calculation (do DOS run with different emin only)"
            )
Exemple #5
0
def parse_kkr_outputfile(out_dict,
                         outfile,
                         outfile_0init,
                         outfile_000,
                         timing_file,
                         potfile_out,
                         nonco_out_file,
                         outfile_2='output.2.txt',
                         skip_readin=False):
    """
    Parser method for the kkr outfile. It returns a dictionary with results
    """
    # scaling factors etc. defined globally
    Ry2eV = get_Ry2eV()
    doscalc = False

    # collection of parsing error messages
    msg_list = []

    try:
        code_version, compile_options, serial_number = get_version_info(
            outfile)
        tmp_dict = {}
        tmp_dict['code_version'] = code_version
        tmp_dict['compile_options'] = compile_options
        tmp_dict['calculation_serial_number'] = serial_number
        out_dict['code_info_group'] = tmp_dict
    except:
        msg = "Error parsing output of KKR: Version Info"
        msg_list.append(msg)

    try:
        nspin = get_nspin(outfile_0init)
        natom = get_natom(outfile_0init)
        newsosol = use_newsosol(outfile_0init)
        out_dict['nspin'] = nspin
        out_dict['number_of_atoms_in_unit_cell'] = natom
        out_dict['use_newsosol'] = newsosol
    except:
        msg = "Error parsing output of KKR: nspin/natom"
        msg_list.append(msg)

    try:
        result = find_warnings(outfile)
        tmp_dict = {}
        tmp_dict['number_of_warnings'] = len(result)
        tmp_dict['warnings_list'] = result
        out_dict['warnings_group'] = tmp_dict
    except:
        msg = "Error parsing output of KKR: search for warnings"
        msg_list.append(msg)

    try:
        result = extract_timings(timing_file)
        out_dict['timings_group'] = result
        out_dict['timings_unit'] = 'seconds'
    except:
        msg = "Error parsing output of KKR: timings"
        msg_list.append(msg)

    try:
        emin, tempr, Nepts, Npol, N1, N2, N3 = get_econt_info(outfile_0init)
        tmp_dict = {}
        tmp_dict['emin'] = emin
        tmp_dict['emin_unit'] = 'Rydberg'
        tmp_dict['number_of_energy_points'] = Nepts
        tmp_dict['temperature'] = tempr
        tmp_dict['temperature_unit'] = 'Kelvin'
        tmp_dict['npol'] = Npol
        tmp_dict['n1'] = N1
        tmp_dict['n2'] = N2
        tmp_dict['n3'] = N3
        out_dict['energy_contour_group'] = tmp_dict
        if Npol == 0:
            doscalc = True
    except:
        msg = "Error parsing output of KKR: energy contour"
        msg_list.append(msg)

    try:
        alat, twopioveralat = get_alatinfo(outfile_0init)
        out_dict['alat_internal'] = alat
        out_dict['two_pi_over_alat_internal'] = twopioveralat
        out_dict['alat_internal_unit'] = 'a_Bohr'
        out_dict['two_pi_over_alat_internal_unit'] = '1/a_Bohr'
    except:
        msg = "Error parsing output of KKR: alat, 2*pi/alat"
        msg_list.append(msg)

    try:
        nkmesh, kmesh_ie = get_kmeshinfo(outfile_0init, outfile_000)
        tmp_dict = {}
        tmp_dict['number_different_kmeshes'] = nkmesh[0]
        tmp_dict['number_kpoints_per_kmesh'] = nkmesh[1]
        tmp_dict['kmesh_energypoint'] = kmesh_ie
        out_dict['kmesh_group'] = tmp_dict
    except:
        msg = "Error parsing output of KKR: kmesh"
        msg_list.append(msg)

    try:
        nsym, nsym_used, desc = get_symmetries(outfile_0init)
        tmp_dict = {}
        tmp_dict['number_of_lattice_symmetries'] = nsym
        tmp_dict['number_of_used_symmetries'] = nsym_used
        tmp_dict['symmetry_description'] = desc
        out_dict['symmetries_group'] = tmp_dict
    except:
        msg = "Error parsing output of KKR: symmetries"
        msg_list.append(msg)

    if not doscalc:  # in case of dos calculation no ewald summation is done
        try:
            rsum, gsum, info = get_ewald(outfile_0init)
            tmp_dict = {}
            tmp_dict['ewald_summation_mode'] = info
            tmp_dict['rsum_cutoff'] = rsum[0]
            tmp_dict['rsum_number_of_vectors'] = rsum[1]
            tmp_dict['rsum_number_of_shells'] = rsum[2]
            tmp_dict['rsum_cutoff_unit'] = 'a_Bohr'
            tmp_dict['gsum_cutoff'] = gsum[0]
            tmp_dict['gsum_number_of_vectors'] = gsum[1]
            tmp_dict['gsum_number_of_shells'] = gsum[2]
            tmp_dict['gsum_cutoff_unit'] = '1/a_Bohr'
            out_dict['ewald_sum_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKR: ewald summation for madelung poterntial"
            msg_list.append(msg)

    try:
        bv, recbv = get_lattice_vectors(outfile_0init)
        out_dict['direct_bravais_matrix'] = bv
        out_dict['reciprocal_bravais_matrix'] = recbv
        out_dict['direct_bravais_matrix_unit'] = 'alat'
        out_dict['reciprocal_bravais_matrix_unit'] = '2*pi / alat'
    except:
        msg = "Error parsing output of KKR: lattice vectors (direct/reciprocal)"
        msg_list.append(msg)

    # this is skipped for qdos run for example
    if not skip_readin:
        try:
            ncore, emax, lmax, descr_max = get_core_states(potfile_out)
            tmp_dict = {}
            tmp_dict['number_of_core_states_per_atom'] = ncore
            tmp_dict['energy_highest_lying_core_state_per_atom'] = emax
            tmp_dict[
                'energy_highest_lying_core_state_per_atom_unit'] = 'Rydberg'
            tmp_dict['descr_highest_lying_core_state_per_atom'] = descr_max
            out_dict['core_states_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKR: core_states"
            msg_list.append(msg)

        tmp_dict = {
        }  # used to group convergence info (rms, rms per atom, charge neutrality)
        # also initialize convegence_group where all info stored for all iterations is kept
        out_dict['convergence_group'] = tmp_dict
        try:
            result, result_atoms_last = get_rms(outfile, outfile_000)
            tmp_dict['rms'] = result[-1]
            tmp_dict['rms_all_iterations'] = result
            tmp_dict['rms_per_atom'] = result_atoms_last
            tmp_dict['rms_unit'] = 'unitless'
            out_dict['convergence_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKR: rms-error"
            msg_list.append(msg)

        try:
            result = get_neutr(outfile)
            tmp_dict['charge_neutrality'] = result[-1]
            out_dict['convergence_group'][
                'charge_neutrality_all_iterations'] = result
            tmp_dict['charge_neutrality_unit'] = 'electrons'
            out_dict['convergence_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKR: charge neutrality"
            msg_list.append(msg)

        tmp_dict = {
        }  # used to group magnetism info (spin and orbital moments)
        try:
            result = get_magtot(outfile)
            if len(result) > 0:
                tmp_dict['total_spin_moment'] = result[-1]
                out_dict['convergence_group'][
                    'total_spin_moment_all_iterations'] = result
                tmp_dict['total_spin_moment_unit'] = 'mu_Bohr'
                out_dict['magnetism_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKR: total magnetic moment"
            msg_list.append(msg)

        try:
            if nspin > 1:
                if not newsosol:
                    #reset automatically to None to turn off reading of nonco angles file
                    nonco_out_file = None

                result, vec, angles = get_spinmom_per_atom(
                    outfile, natom, nonco_out_file)
                if len(result) > 0:
                    tmp_dict['spin_moment_per_atom'] = result[-1, :]
                    if newsosol:
                        tmp_dict['spin_moment_vector_per_atom'] = vec[:]
                        tmp_dict['spin_moment_angles_per_atom'] = angles[:]
                        tmp_dict['spin_moment_angles_per_atom_unit'] = 'degree'
                    out_dict['convergence_group'][
                        'spin_moment_per_atom_all_iterations'] = result[:, :]
                    tmp_dict['spin_moment_unit'] = 'mu_Bohr'
                    out_dict['magnetism_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKR: spin moment per atom"
            msg_list.append(msg)

        # add orbital moments to magnetis group in parser output
        try:
            if nspin > 1 and newsosol:
                #TODO orbital moment full vectors
                # so far the KKR code writes only the component of the orbital moment
                # parallel to the spin moment, thus vec and angles are returned empty
                # by construction. This might change in the future
                #result, vec, angles = get_orbmom(outfile, natom, nonco_angles_orbmom)
                # so for now return only result= array containing all iterations, all atoms, orbital moment parallel to spin quantization axis
                result = get_orbmom(outfile, natom)
                if len(result) > 0:
                    tmp_dict['total_orbital_moment'] = sum(result[-1, :])
                    tmp_dict['orbital_moment_per_atom'] = result[-1, :]
                    #tmp_dict['orbital_moment_vector_per_atom'] = vec[-1,:]
                    #tmp_dict['orbital_moment_angles_per_atom'] = angles[-1,:]
                    out_dict['convergence_group'][
                        'orbital_moment_per_atom_all_iterations'] = result[:, :]
                    tmp_dict['orbital_moment_unit'] = 'mu_Bohr'
                    #tmp_dict['orbital_moment_angles_per_atom_unit'] = 'degree'
                    out_dict['magnetism_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKR: orbital moment"
            msg_list.append(msg)

        try:
            result = get_EF(outfile)
            out_dict['fermi_energy'] = result[-1]
            out_dict['fermi_energy_units'] = 'Ry'
            out_dict['convergence_group'][
                'fermi_energy_all_iterations'] = result
            out_dict['convergence_group'][
                'fermi_energy_all_iterations_units'] = 'Ry'
        except:
            msg = "Error parsing output of KKR: EF"
            msg_list.append(msg)

        try:
            result = get_DOS_EF(outfile)
            out_dict['dos_at_fermi_energy'] = result[-1]
            out_dict['convergence_group'][
                'dos_at_fermi_energy_all_iterations'] = result
        except:
            msg = "Error parsing output of KKR: DOS@EF"
            msg_list.append(msg)

        try:
            result = get_Etot(outfile)
            out_dict['energy'] = result[-1] * Ry2eV
            out_dict['energy_unit'] = 'eV'
            out_dict['total_energy_Ry'] = result[-1]
            out_dict['total_energy_Ry_unit'] = 'Rydberg'
            out_dict['convergence_group'][
                'total_energy_Ry_all_iterations'] = result
        except:
            msg = "Error parsing output of KKR: total energy"
            msg_list.append(msg)

        try:
            result = get_single_particle_energies(outfile_000)
            out_dict['single_particle_energies'] = result * Ry2eV
            out_dict['single_particle_energies_unit'] = 'eV'
        except:
            msg = "Error parsing output of KKR: single particle energies"
            msg_list.append(msg)

        try:
            result_WS, result_tot, result_C = get_charges_per_atom(outfile_000)
            niter = len(out_dict['convergence_group']['rms_all_iterations'])
            natyp = int(len(result_tot) // niter)
            out_dict['total_charge_per_atom'] = result_tot[-natyp:]
            out_dict['charge_core_states_per_atom'] = result_C[-natyp:]
            # this check deals with the DOS case where output is slightly different
            if len(result_WS) == len(result_C):
                out_dict['charge_valence_states_per_atom'] = result_WS[
                    -natyp:] - result_C[-natyp:]
            out_dict['total_charge_per_atom_unit'] = 'electron charge'
            out_dict['charge_core_states_per_atom_unit'] = 'electron charge'
            out_dict['charge_valence_states_per_atom_unit'] = 'electron charge'
        except:
            msg = "Error parsing output of KKR: charges"
            msg_list.append(msg)

        try:
            try:
                niter, nitermax, converged, nmax_reached, mixinfo = get_scfinfo(
                    outfile_0init, outfile_000, outfile)
            except IndexError:
                niter, nitermax, converged, nmax_reached, mixinfo = get_scfinfo(
                    outfile_0init, outfile_2, outfile)
            out_dict['convergence_group']['number_of_iterations'] = niter
            out_dict['convergence_group'][
                'number_of_iterations_max'] = nitermax
            out_dict['convergence_group']['calculation_converged'] = converged
            out_dict['convergence_group']['nsteps_exhausted'] = nmax_reached
            out_dict['convergence_group']['imix'] = mixinfo[0]
            out_dict['convergence_group']['strmix'] = mixinfo[1]
            out_dict['convergence_group']['qbound'] = mixinfo[2]
            out_dict['convergence_group']['fcm'] = mixinfo[3]
            out_dict['convergence_group']['idtbry'] = mixinfo[4]
            out_dict['convergence_group']['brymix'] = mixinfo[5]
        except:
            msg = "Error parsing output of KKR: scfinfo"
            msg_list.append(msg)

    #convert numpy arrays to standard python lists
    out_dict = convert_to_pystd(out_dict)

    # return output with error messages if there are any
    if len(msg_list) > 0:
        return False, msg_list, out_dict
    else:
        return True, [], out_dict
def parse_voronoi_output(out_dict, outfile, potfile, atominfo, radii,
                         inputfile):
    """
    Parse output of voronoi calculation and return (success, error_messages_list, out_dict)
    """
    # for collection of error messages:
    msg_list = []

    try:
        code_version, compile_options, serial_number = get_version_info(
            outfile)
        tmp_dict = {}
        tmp_dict['code_version'] = code_version
        tmp_dict['compile_options'] = compile_options
        tmp_dict['calculation_serial_number'] = serial_number
        out_dict['code_info_group'] = tmp_dict
    except:
        msg = "Error parsing output of voronoi: Version Info"
        msg_list.append(msg)

    try:
        emin, e_core_max = check_voronoi_output(potfile, outfile)
        out_dict['emin'] = emin
        out_dict['emin_units'] = 'Ry'
        diff_emin_ef = emin - get_ef_from_potfile(potfile)
        out_dict['emin_minus_efermi_Ry'] = diff_emin_ef
        out_dict['emin_minus_efermi'] = diff_emin_ef * get_Ry2eV()
        out_dict['emin_minus_efermi_Ry_units'] = 'Ry'
        out_dict['emin_minus_efermi_units'] = 'eV'
    except:
        msg = "Error parsing output of voronoi: 'EMIN'"
        msg_list.append(msg)

    # parse
    try:
        ncore, emax, lmax, descr_max = get_core_states(potfile)
        tmp_dict = {}
        tmp_dict['number_of_core_states_per_atom'] = ncore
        tmp_dict['energy_highest_lying_core_state_per_atom'] = emax
        tmp_dict['energy_highest_lying_core_state_per_atom_unit'] = 'Rydberg'
        tmp_dict['descr_highest_lying_core_state_per_atom'] = descr_max
        out_dict['core_states_group'] = tmp_dict
    except:
        msg = "Error parsing output of voronoi: core_states"
        msg_list.append(msg)

    try:
        Ncls, natom, results = get_cls_info(outfile)
        clsinfo = []
        tmpdict_all = {}
        for icls in range(natom):
            tmpdict = {}
            tmpdict['iatom'] = results[icls][0]
            tmpdict['refpot'] = results[icls][1]
            tmpdict['rmt_ref'] = results[icls][2]
            tmpdict['tb_cluster_id'] = results[icls][3]
            tmpdict['sites'] = results[icls][4]
            clsinfo.append(tmpdict)
        tmpdict_all['cluster_info_atoms'] = clsinfo
        tmpdict_all['number_of_clusters'] = Ncls
        out_dict['cluster_info_group'] = tmpdict_all
    except:
        msg = "Error parsing output of voronoi: Cluster Info"
        msg_list.append(msg)

    try:
        out_dict['start_from_jellium_potentials'] = startpot_jellium(outfile)
    except:
        msg = "Error parsing output of voronoi: Jellium startpot"
        msg_list.append(msg)

    try:
        natyp, naez, shapes = get_shape_array(outfile, atominfo)
        out_dict['shapes'] = shapes
    except:
        msg = "Error parsing output of voronoi: SHAPE Info"
        msg_list.append(msg)

    try:
        Vtot, results = get_volumes(outfile)
        tmp_dict = {}
        tmp_dict['volume_total'] = Vtot
        tmpdict_all = []
        for icls in range(naez):
            tmpdict = {}
            tmpdict['iatom'] = results[icls][0]
            tmpdict['v_atom'] = results[icls][1]
            tmpdict_all.append(tmpdict)
        tmp_dict['volume_atoms'] = tmpdict_all
        tmp_dict['volume_unit'] = 'alat^3'
        out_dict['volumes_group'] = tmp_dict
    except:
        msg = "Error parsing output of voronoi: Volume Info"
        msg_list.append(msg)

    try:
        results = get_radii(naez, radii)
        tmpdict_all = []
        for icls in range(naez):
            tmpdict = {}
            tmpdict['iatom'] = results[icls][0]
            tmpdict['rmt0'] = results[icls][1]
            tmpdict['rout'] = results[icls][2]
            tmpdict['dist_nn'] = results[icls][4]
            tmpdict['rmt0_over_rout'] = results[icls][3]
            tmpdict['rout_over_dist_nn'] = results[icls][5]
            tmpdict_all.append(tmpdict)
        tmpdict_all.append({'radii_units': 'alat'})
        out_dict['radii_atoms_group'] = tmpdict_all
    except:
        msg = "Error parsing output of voronoi: radii.dat Info"
        msg_list.append(msg)

    try:
        results = get_fpradius(naez, atominfo)
        out_dict['fpradius_atoms'] = results
        out_dict['fpradius_atoms_unit'] = 'alat'
    except:
        msg = "Error parsing output of voronoi: full potential radius"
        msg_list.append(msg)

    try:
        result = get_alat(inputfile)
        out_dict['alat'] = result
        out_dict['alat_unit'] = 'a_Bohr'
    except:
        msg = "Error parsing output of voronoi: alat"
        msg_list.append(msg)

    try:
        result = get_radial_meshpoints(potfile)
        out_dict['radial_meshpoints'] = result
    except:
        msg = "Error parsing output of voronoi: radial meshpoints"
        msg_list.append(msg)

    # some consistency checks comparing lists with natyp/naez numbers
    #TODO implement checks

    #convert numpy arrays to standard python lists
    out_dict = convert_to_pystd(out_dict)

    # return output with error messages if there are any
    if len(msg_list) > 0:
        return False, msg_list, out_dict
    else:
        return True, [], out_dict
    def parse_kkrimp_outputfile(self, out_dict, file_dict):
        """
        Main parser function for kkrimp, read information from files in file_dict and fills out_dict
        :param out_dict: dictionary that is filled with parsed output of the KKRimp calculation
        :param file_dict: dictionary of files that are parsed
        :returns: success (bool), msg_list(list of error/warning messages of parser), out_dict (filled dict of parsed output)
        :note: file_dict should contain the following keys
            * 'outfile', the std_out of the KKRimp calculation
            * 'out_log', the out_log.000.txt file
            * 'out_pot', the output potential
            * 'out_enersp_at', the out_energysp_per_atom_eV file
            * 'out_enertot_at', the out_energytotal_per_atom_eV file
            * 'out_timing', the timing file
            * 'kkrflex_llyfac', the file for the Lloyd factor
            * 'kkrflex_angles', the nonco_angles file for the KKRimp calculation
            * 'out_spinmoms', the output spin moments file
            * 'out_orbmoms', the output orbital moments file
        """
        from masci_tools.io.parsers.kkrparser_functions import get_rms, find_warnings, get_charges_per_atom, get_core_states
        from masci_tools.io.common_functions import get_version_info, get_Ry2eV

        Ry2eV = get_Ry2eV()
        msg_list = []
        files = file_dict

        try:
            code_version, compile_options, serial_number = get_version_info(
                files['out_log'])
            tmp_dict = {}
            tmp_dict['code_version'] = code_version
            tmp_dict['compile_options'] = compile_options
            tmp_dict['calculation_serial_number'] = serial_number
            out_dict['code_info_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKRimp: Version Info"
            msg_list.append(msg)

        tmp_dict = {
        }  # used to group convergence info (rms, rms per atom, charge neutrality)
        # also initialize convegence_group where all info stored for all iterations is kept
        out_dict['convergence_group'] = tmp_dict
        try:
            result, result_atoms_last = get_rms(files['outfile'],
                                                files['out_log'])
            tmp_dict['rms'] = result[-1]
            tmp_dict['rms_all_iterations'] = result
            tmp_dict['rms_per_atom'] = result_atoms_last
            tmp_dict['rms_unit'] = 'unitless'
            out_dict['convergence_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKRimp: rms-error"
            msg_list.append(msg)

        try:
            natom = self._get_natom(files['out_log'])
            nspin = self._get_nspin(files['out_log'], natom)
            newsosol = self._get_newsosol(files['out_log'])
            out_dict['nspin'] = nspin
            out_dict['number_of_atoms_in_unit_cell'] = natom
            out_dict['use_newsosol'] = newsosol
        except:
            msg = "Error parsing output of KKRimp: nspin/natom"
            msg_list.append(msg)

        tmp_dict = {
        }  # used to group magnetism info (spin and orbital moments)
        try:
            if nspin > 1 and newsosol:
                spinmom_vec, spinmom_vec_all, magtot = self._get_spinmom_per_atom(
                    files['out_spinmoms'], natom)
                tmp_dict['total_spin_moment'] = magtot
                out_dict['convergence_group'][
                    'spin_moment_per_atom'] = spinmom_vec
                out_dict['convergence_group'][
                    'spin_moment_per_atom_all_iterations'] = spinmom_vec_all
                tmp_dict['total_spin_moment_unit'] = 'mu_Bohr'
                out_dict['magnetism_group'] = tmp_dict
            elif nspin > 1:
                spinmom_vec, spinmom_vec_all, magtot = self._get_magtot(
                    files['out_log'], natom)
                tmp_dict['total_spin_moment'] = magtot
                out_dict['convergence_group'][
                    'spin_moment_per_atom'] = spinmom_vec
                out_dict['convergence_group'][
                    'spin_moment_per_atom_all_iterations'] = spinmom_vec_all
                tmp_dict['total_spin_moment_unit'] = 'mu_Bohr'
                out_dict['magnetism_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKRimp: spin moment per atom"
            msg_list.append(msg)

        # add orbital moments to magnetism group in parser output
        try:
            if nspin > 1 and newsosol and files['out_orbmoms'] is not None:
                orbmom_atom, orbmom_atom_all = self._get_orbmom_per_atom(
                    files['out_orbmoms'], natom)
                tmp_dict['orbital_moment_per_atom'] = orbmom_atom
                out_dict['convergence_group'][
                    'orbital_moment_per_atom_all_iterations'] = orbmom_atom_all
                tmp_dict['orbital_moment_unit'] = 'mu_Bohr'
                out_dict['magnetism_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKRimp: orbital moment"
            msg_list.append(msg)

        try:
            result = self._get_EF_potfile(files['out_pot'])
            out_dict['fermi_energy'] = result
            out_dict['fermi_energy_units'] = 'Ry'
        except:
            msg = "Error parsing output of KKRimp: EF"
            msg_list.append(msg)

        try:
            result = self._get_Etot(files['out_log'])
            out_dict['energy'] = result[-1] * Ry2eV
            out_dict['energy_unit'] = 'eV'
            out_dict['total_energy_Ry'] = result[-1]
            out_dict['total_energy_Ry_unit'] = 'Rydberg'
            out_dict['convergence_group'][
                'total_energy_Ry_all_iterations'] = result
        except:
            msg = "Error parsing output of KKRimp: total energy"
            msg_list.append(msg)

        try:
            result = find_warnings(files['outfile'])
            tmp_dict = {}
            tmp_dict['number_of_warnings'] = len(result)
            tmp_dict['warnings_list'] = result
            out_dict['warnings_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKRimp: search for warnings"
            msg_list.append(msg)

        try:
            result = self._extract_timings(files['out_timing'])
            out_dict['timings_group'] = result
            out_dict['timings_unit'] = 'seconds'
        except:
            msg = "Error parsing output of KKRimp: timings"
            msg_list.append(msg)

        try:
            esp_at, etot_at = self._get_energies_atom(files['out_enersp_at'],
                                                      files['out_enertot_at'],
                                                      natom)
            out_dict['single_particle_energies'] = esp_at * Ry2eV
            out_dict['single_particle_energies_unit'] = 'eV'
            out_dict['total_energies_atom'] = etot_at * Ry2eV
            out_dict['total_energies_atom_unit'] = 'eV'
        except:
            msg = "Error parsing output of KKRimp: single particle energies"
            msg_list.append(msg)

        try:
            result_WS, result_tot, result_C = get_charges_per_atom(
                files['out_log'])
            niter = len(out_dict['convergence_group']['rms_all_iterations'])
            natyp = int(len(result_tot) / niter)
            out_dict['total_charge_per_atom'] = result_WS[-natyp:]
            out_dict['charge_core_states_per_atom'] = result_C[-natyp:]
            # this check deals with the DOS case where output is slightly different
            if len(result_WS) == len(result_C):
                out_dict['charge_valence_states_per_atom'] = result_WS[
                    -natyp:] - result_C[-natyp:]
            out_dict['total_charge_per_atom_unit'] = 'electron charge'
            out_dict['charge_core_states_per_atom_unit'] = 'electron charge'
            out_dict['charge_valence_states_per_atom_unit'] = 'electron charge'
        except:
            msg = "Error parsing output of KKRimp: charges"
            msg_list.append(msg)

        try:
            econt = self._get_econt_info(files['out_log'])
            tmp_dict = {}
            tmp_dict['emin'] = econt.get('emin')
            tmp_dict['emin_unit'] = 'Rydberg'
            tmp_dict['number_of_energy_points'] = econt.get('Nepts')
            tmp_dict['epoints_contour'] = econt.get('epts')
            tmp_dict['epoints_contour_unit'] = 'Rydberg'
            tmp_dict['epoints_weights'] = econt.get('weights')
            out_dict['energy_contour_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKRimp: energy contour"
            msg_list.append(msg)

        try:
            ncore, emax, lmax, descr_max = get_core_states(files['out_pot'])
            tmp_dict = {}
            tmp_dict['number_of_core_states_per_atom'] = ncore
            tmp_dict['energy_highest_lying_core_state_per_atom'] = emax
            tmp_dict[
                'energy_highest_lying_core_state_per_atom_unit'] = 'Rydberg'
            tmp_dict['descr_highest_lying_core_state_per_atom'] = descr_max
            out_dict['core_states_group'] = tmp_dict
        except:
            msg = "Error parsing output of KKRimp: core_states"
            msg_list.append(msg)

        try:
            niter, nitermax, converged, nmax_reached, mixinfo = self._get_scfinfo(
                files['out_log'])
            out_dict['convergence_group']['number_of_iterations'] = niter
            out_dict['convergence_group'][
                'number_of_iterations_max'] = nitermax
            out_dict['convergence_group']['calculation_converged'] = converged
            out_dict['convergence_group']['nsteps_exhausted'] = nmax_reached
            out_dict['convergence_group']['imix'] = mixinfo[0]
            out_dict['convergence_group']['strmix'] = mixinfo[1]
            out_dict['convergence_group']['qbound'] = mixinfo[2]
            out_dict['convergence_group']['fcm'] = mixinfo[3]
            out_dict['convergence_group']['brymix'] = mixinfo[1]
        except:
            msg = "Error parsing output of KKRimp: scfinfo"
            msg_list.append(msg)

        #convert arrays to lists
        from numpy import ndarray
        for key in list(out_dict.keys()):
            if type(out_dict[key]) == ndarray:
                out_dict[key] = list(out_dict[key])
            elif type(out_dict[key]) == dict:
                for subkey in list(out_dict[key].keys()):
                    if type(out_dict[key][subkey]) == ndarray:
                        out_dict[key][subkey] = (
                            out_dict[key][subkey]).tolist()

        # return output with error messages if there are any
        if len(msg_list) > 0:
            return False, msg_list, out_dict
        else:
            return True, [], out_dict
Exemple #8
0
def parse_impdosfiles(dos_abspath, natom, nspin, ef):
    """
    Read `out_ldos*` files and create XyData node with l-resolved DOS (+node for interpolated DOS if files are found)

    Inputs:
    :param dos_abspath: absolute path to folder where `out_ldos*` files reside (AiiDA Str object)
    :param natom: number of atoms (AiiDA Int object)
    :param nspin: number of spin channels (AiiDA Int object)
    :param ef: Fermi energy in Ry units (AiiDA Float object)

    Returns:
    output dictionary containing
      output = {'dos_data': dosnode, 'dos_data_interpol': dosnode2}
    where `dosnode` and `dosnode2` are AiiDA XyData objects
    """
    from masci_tools.io.common_functions import get_Ry2eV, get_ef_from_potfile
    from numpy import loadtxt, array

    # add '/' if missing from path
    abspath = dos_abspath.value
    if abspath[-1] != '/': abspath += '/'

    # read dos files
    dos, dos_int = [], []
    for iatom in range(1, natom.value + 1):
        for ispin in range(1, nspin.value + 1):
            with open(abspath + 'out_ldos.atom=%0.2i_spin%i.dat' %
                      (iatom, ispin)) as dosfile:
                tmp = loadtxt(dosfile)
                dos.append(tmp)
            with open(abspath + 'out_ldos.interpol.atom=%0.2i_spin%i.dat' %
                      (iatom, ispin)) as dosfile:
                tmp = loadtxt(dosfile)
                dos_int.append(tmp)
    dos, dos_int = array(dos), array(dos_int)

    # convert to eV units
    eVscale = get_Ry2eV()
    dos[:, :, 0] = (dos[:, :, 0] - ef.value) * eVscale
    dos[:, :, 1:] = dos[:, :, 1:] / eVscale
    dos_int[:, :, 0] = (dos_int[:, :, 0] - ef.value) * eVscale
    dos_int[:, :, 1:] = dos_int[:, :, 1:] / eVscale

    # create output nodes
    dosnode = XyData()
    dosnode.label = 'dos_data'
    dosnode.description = 'Array data containing uniterpolated DOS (i.e. dos at finite imaginary part of energy). 3D array with (atoms, energy point, l-channel) dimensions.'
    dosnode.set_x(dos[:, :, 0], 'E-EF', 'eV')

    name = ['tot', 's', 'p', 'd', 'f', 'g']
    name = name[:len(dos[0, 0, 1:]) - 1] + ['ns']

    ylists = [[], [], []]
    for l in range(len(name)):
        ylists[0].append(dos[:, :, 1 + l])
        ylists[1].append('dos ' + name[l])
        ylists[2].append('states/eV')
    dosnode.set_y(ylists[0], ylists[1], ylists[2])

    # node for interpolated DOS
    dosnode2 = XyData()
    dosnode2.label = 'dos_interpol_data'
    dosnode2.description = 'Array data containing iterpolated DOS (i.e. dos at finite imaginary part of energy). 3D array with (atoms, energy point, l-channel) dimensions.'
    dosnode2.set_x(dos_int[:, :, 0], 'E-EF', 'eV')
    ylists = [[], [], []]
    for l in range(len(name)):
        ylists[0].append(dos_int[:, :, 1 + l])
        ylists[1].append('interpolated dos ' + name[l])
        ylists[2].append('states/eV')
    dosnode2.set_y(ylists[0], ylists[1], ylists[2])

    output = {'dos_data': dosnode, 'dos_data_interpol': dosnode2}

    return output
    def set_params_flex(self):
        """
        Take input parameter node and change to input from wf_parameter and options
        """

        self.report('INFO: setting parameters ...')

        params = self.ctx.input_params_KKR
        input_dict = params.get_dict()
        para_check = kkrparams()

        # step 1: try to fill keywords
        try:
            for key, val in input_dict.items():
                para_check.set_value(key, val, silent=True)
        except:
            return self.exit_codes.ERROR_INVALID_CALC_PARAMETERS

        # step 2: check if all mandatory keys are there
        label = ''
        descr = ''
        missing_list = para_check.get_missing_keys(use_aiida=True)
        if missing_list != []:
            kkrdefaults = kkrparams.get_KKRcalc_parameter_defaults()[0]
            kkrdefaults_updated = []
            for key_default, val_default in list(kkrdefaults.items()):
                if key_default in missing_list:
                    para_check.set_value(key_default,
                                         kkrdefaults.get(key_default),
                                         silent=True)
                    kkrdefaults_updated.append(key_default)
                    missing_list.remove(key_default)
            if len(missing_list) > 0:
                self.report('ERROR: calc_parameters misses keys: {}'.format(
                    missing_list))
                return self.exit_codes.ERROR_CALC_PARAMETERS_INCOMPLETE

            else:
                self.report(
                    'updated KKR parameter node with default values: {}'.
                    format(kkrdefaults_updated))
                label = 'add_defaults_'
                descr = 'added missing default keys, '

        # updatedict contains all things that will be updated with update_params_wf later on
        updatedict = {}

        runopt = para_check.get_dict().get('RUNOPT', None)
        if runopt == None:
            runopt = []

        # overwrite some parameters of the KKR calculation by hand before setting mandatory keys
        if "params_kkr_overwrite" in self.inputs:
            for key, val in self.inputs.params_kkr_overwrite.get_dict().items(
            ):
                if key != runopt:
                    updatedict[key] = val
                else:
                    runopt = val
                self.report(
                    'INFO: overwriting KKR parameter: {} with {} from params_kkr_overwrite input node'
                    .format(key, val))

        runopt = [i.strip() for i in runopt]
        if 'KKRFLEX' not in runopt:
            runopt.append('KKRFLEX')

        updatedict['RUNOPT'] = runopt

        self.report('INFO: RUNOPT set to: {}'.format(runopt))

        if 'wf_parameters' in self.inputs:
            if self.ctx.dos_run:
                for key, val in {
                        'EMIN': self.ctx.dos_params_dict['emin'],
                        'EMAX': self.ctx.dos_params_dict['emax'],
                        'NPT2': self.ctx.dos_params_dict['nepts'],
                        'NPOL': 0,
                        'NPT1': 0,
                        'NPT3': 0,
                        'BZDIVIDE': self.ctx.dos_params_dict['kmesh'],
                        'IEMXD': self.ctx.dos_params_dict['nepts'],
                        'TEMPR': self.ctx.dos_params_dict['tempr']
                }.items():
                    updatedict[key] = val
            elif self.ctx.ef_shift != 0:
                # extract old Fermi energy in Ry
                remote_data_parent = self.inputs.remote_data
                parent_calc = remote_data_parent.get_incoming(
                    link_label_filter='remote_folder').first().node
                ef_old = parent_calc.outputs.output_parameters.get_dict().get(
                    'fermi_energy')
                # get Fermi energy shift in eV
                ef_shift = self.ctx.ef_shift  #set new E_F in eV
                # calculate new Fermi energy in Ry
                ef_new = (ef_old + ef_shift / get_Ry2eV())
                self.report(
                    'INFO: ef_old + ef_shift = ef_new: {} eV + {} eV = {} eV'.
                    format(ef_old * get_Ry2eV(), ef_shift,
                           ef_new * get_Ry2eV()))
                updatedict['ef_set'] = ef_new

        #construct the final param node containing all of the params
        updatenode = Dict(dict=updatedict)
        updatenode.label = label + 'KKRparam_flex'
        updatenode.description = descr + 'KKR parameter node extracted from parent parameters and wf_parameter and options input node.'
        paranode_flex = update_params_wf(self.ctx.input_params_KKR, updatenode)
        self.ctx.flex_kkrparams = paranode_flex
        self.ctx.flex_runopt = runopt

        self.report('INFO: Updated params= {}'.format(
            paranode_flex.get_dict()))
Exemple #10
0
    def collect_data_and_fit(self):
        """
        collect output of KKR calculations and perform eos fitting to collect results
        """
        self.report('INFO: collect kkr results and fit data')
        calc_uuids = self.ctx.kkr_calc_uuids
        etot = []
        for iic in range(len(calc_uuids)):
            uuid = calc_uuids[iic]
            n = load_node(uuid)
            try:
                d_result = n.outputs.output_kkr_scf_wc_ParameterResults.get_dict(
                )
                self.report(
                    'INFO: extracting output of calculation {}: successful={}, rms={}'
                    .format(uuid, d_result[u'successful'],
                            d_result[u'convergence_value']))
                if d_result[u'successful']:
                    pk_last_calc = d_result['last_calc_nodeinfo']['pk']
                    n2 = load_node(pk_last_calc)
                    scale = self.ctx.scale_factors[iic]
                    ener = n2.outputs.output_parameters.get_dict(
                    )['total_energy_Ry']
                    rms = d_result[u'convergence_value']
                    scaled_struc = self.ctx.scaled_structures[iic]
                    v = scaled_struc.get_cell_volume()
                    if rms <= self.ctx.rms_threshold:  # only take those calculations which
                        etot.append([scale, ener, v, rms])
                    else:
                        warn = 'rms of calculation with uuid={} not low enough ({} > {})'.format(
                            uuid, rms, self.ctx.rms_threshold)
                        self.report('WARNING: {}'.format(warn))
                        self.ctx.warnings.append(warn)
            except:
                warn = 'calculation with uuid={} not successful'.format(uuid)
                self.report('WARNING: {}'.format(warn))
                self.ctx.warnings.append(warn)

        # collect calculation outcome
        etot = array(etot)
        self.report('INFO: collected data from calculations= {}'.format(etot))

        # check if at least 3 points were successful (otherwise fit does not work)
        if len(etot) < 3:
            return self.exit_codes.ERROR_NOT_ENOUGH_SUCCESSFUL_CALCS

        scalings = etot[:, 0]
        rms = etot[:, -1]
        # convert to eV and per atom units
        etot = etot / len(scaled_struc.sites)  # per atom values
        etot[:, 1] = etot[:, 1] * get_Ry2eV()  # convert energy from Ry to eV
        volumes, energies = etot[:, 2], etot[:, 1]

        # do multiple fits to data
        self.report('INFO: output of fits:')
        self.report('{:18} {:8} {:7} {:7}'.format('fitfunc', 'v0', 'e0', 'B'))
        self.report('-----------------------------------------')
        fitnames = self.ctx.fitnames
        alldat = []
        fitdata = {}
        for fitfunc in fitnames:
            try:
                eos = EquationOfState(volumes, energies, eos=fitfunc)
                v0, e0, B = eos.fit()
                fitdata[fitfunc] = [v0, e0, B]
                alldat.append([v0, e0, B])
                self.report('{:16} {:8.3f} {:7.3f} {:7.3f}'.format(
                    fitfunc, v0, e0, B))
            except:  # capture all errors and mark fit as unsuccessful
                self.ctx.warnings.append(
                    'fit unsuccessful for {} function'.format(fitfunc))
                if fitfunc == self.ctx.fitfunc_gs_out:
                    self.ctx.successful = False
        alldat = array(alldat)
        self.report('-----------------------------------------')
        self.report('{:16} {:8.3f} {:7.3f} {:7.3f}'.format(
            'mean', mean(alldat[:, 0]), mean(alldat[:, 1]), mean(alldat[:,
                                                                        2])))
        self.report('{:16} {:8.3f} {:7.3f} {:7.3f}'.format(
            'std', std(alldat[:, 0]), std(alldat[:, 1]), std(alldat[:, 2])))

        # store results in context
        self.ctx.volumes = volumes
        self.ctx.energies = energies
        self.ctx.scalings = scalings
        self.ctx.rms = rms
        self.ctx.fitdata = fitdata
        self.ctx.fit_mean_values = {
            '<v0>': mean(alldat[:, 0]),
            '<e0>': mean(alldat[:, 1]),
            '<B>': mean(alldat[:, 2])
        }
        self.ctx.fit_std_values = {
            's_v0': std(alldat[:, 0]),
            's_e0': std(alldat[:, 1]),
            's_B': std(alldat[:, 2])
        }