Source code for aiida_lsmo.utils.cp2k_utils

# -*- coding: utf-8 -*-
"""Utilities related to CP2K."""
from aiida_lsmo.utils import HARTREE2EV


[docs]def get_kinds_info(atoms): """Get kinds information from ASE atoms :param atoms: ASE atoms instance :returns: list of kind_info dictionaries (keys: 'kind', 'element', 'magnetization') """ symbols = sorted(set(atoms.get_chemical_symbols())) kinds_info = [] for symbol in symbols: ats = [atom for atom in atoms if atom.symbol == symbol] tags = {} for atom in ats: # we assume that atoms are already tagged properly (atoms with the same tag have the same properties) tags[atom.tag] = {'element': atom.symbol, 'magnetization': {atom.magmom}, 'tag': {atom.tag}} if len(tags) == 1: kind = tags[0] kind['kind'] = kind['element'] kinds_info.append(kind) else: for tag, kind in tags.items(): kind['kind'] = f"{kind['element']}{str(tag)}" kinds_info.append(kind) return kinds_info
[docs]def get_multiplicity_section(atoms, protocol): """ Compute the total multiplicity of the structure by summing the atomic magnetizations. multiplicity = 1 + sum_i ( natoms_i * magnetization_i ), for each atom_type i = 1 + sum_i magnetization_j, for each atomic site j :param atoms: ASE atoms instance :param protocol: protocol dict :returns: dict (for cp2k input) """ if protocol['initial_magnetization'] == 'zero': # base multiplicity on number of electrons # (even atomic number <=> even number of valence electrons) is_even = sum(atoms.get_atomic_numbers()) % 2 == 0 if is_even: multiplicity = 1 else: multiplicity = 2 else: # base multiplicity on starting magnetization multiplicity = 1 + sum([atom.magmom for atom in atoms]) multiplicity = int(round(multiplicity)) multiplicity_dict = {'FORCE_EVAL': {'DFT': {'MULTIPLICITY': multiplicity}}} if multiplicity != 1: multiplicity_dict['FORCE_EVAL']['DFT']['UKS'] = True return multiplicity_dict
[docs]def get_kinds_section(atoms, protocol, with_ghost_atoms=False): """ Write the &KIND sections given the structure and the settings_dict :param atoms: ASE atoms instance :param protocol: protocol dict :param with_ghost_atoms: if true, add ghost atoms for BSSE counterpoise correction (optional) """ kinds_info = get_kinds_info(atoms) kinds = [] for kind_info in kinds_info: kinds.append({ '_': kind_info['kind'], 'ELEMENT': kind_info['element'], 'BASIS_SET': protocol['basis_set'][kind_info['element']], 'POTENTIAL': protocol['pseudopotential'][kind_info['element']], 'MAGNETIZATION': kind_info['magnetization'], }) if with_ghost_atoms: kinds.append({ '_': kind_info['kind'] + '_ghost', 'ELEMENT': kind_info['element'], 'BASIS_SET': protocol['basis_set'][kind_info['element']], 'GHOST': True }) return {'FORCE_EVAL': {'SUBSYS': {'KIND': kinds}}}
[docs]def get_bsse_section(natoms_a, natoms_b, mult_a=1, mult_b=1, charge_a=0, charge_b=0): # pylint: disable=too-many-arguments """Get the &FORCE_EVAL/&BSSE section.""" bsse_section = { 'FORCE_EVAL': { 'BSSE' : { 'FRAGMENT': [{ 'LIST': '1..{}'.format(natoms_a) }, { 'LIST': '{}..{}'.format(natoms_a + 1, natoms_a + natoms_b) }], 'CONFIGURATION': [ { # A fragment with basis set A 'MULTIPLICITY': mult_a, 'CHARGE': charge_a, 'GLB_CONF': '1 0', 'SUB_CONF': '1 0', }, { # B fragment with basis set B 'MULTIPLICITY': mult_b, 'CHARGE': charge_b, 'GLB_CONF': '0 1', 'SUB_CONF': '0 1', }, { # A fragment with basis set A+B 'MULTIPLICITY': mult_a, 'CHARGE': charge_a, 'GLB_CONF': '1 1', 'SUB_CONF': '1 0', }, { # B fragment with basis set A+B 'MULTIPLICITY': mult_b, 'CHARGE': charge_b, 'GLB_CONF': '1 1', 'SUB_CONF': '0 1', }, { # A+B fragments with basis set A+B 'MULTIPLICITY': mult_a + mult_b - 1, 'CHARGE': charge_a + charge_b, 'GLB_CONF': '1 1', 'SUB_CONF': '1 1', } ] } } } return bsse_section
# Functions to parse results
[docs]def ot_has_small_bandgap(cp2k_input, cp2k_output, bandgap_thr_ev): """ Returns True if the calculation used OT and had a smaller bandgap then the guess needed for the OT. (NOTE: It has been observed also negative bandgap with OT in CP2K!) cp2k_input: dict cp2k_output: dict bandgap_thr_ev: float [eV] """ list_true = [True, 'T', 't', '.TRUE.', 'True', 'true'] #add more? try: ot_settings = cp2k_input['FORCE_EVAL']['DFT']['SCF']['OT'] if '_' not in ot_settings.keys() or ot_settings['_'] in list_true: #pylint: disable=simplifiable-if-statement using_ot = True else: using_ot = False except KeyError: using_ot = False min_bandgap_ev = min(cp2k_output['bandgap_spin1_au'], cp2k_output['bandgap_spin2_au']) * HARTREE2EV is_bandgap_small = (min_bandgap_ev < bandgap_thr_ev) return using_ot and is_bandgap_small