Source code for aiida_vasp.utils.workchains
"""
Utils for the workchains.
-------------------------
Auxiliary routines that are not part of any of the workchain classes, but needed
to make code more compact in the workchains.
"""
# pylint: disable=import-outside-toplevel
from copy import deepcopy
import numpy as np
from aiida.common.extendeddicts import AttributeDict
from aiida.engine.processes.exit_code import ExitCode
from aiida.orm import Dict
from aiida.plugins import DataFactory
from aiida_vasp.utils.extended_dicts import delete_keys_from_dict
[docs]
def compare_structures(structure_a, structure_b):
"""Compare two StructureData objects A, B and return a delta (A - B) of the relevant properties."""
delta = AttributeDict()
delta.absolute = AttributeDict()
delta.relative = AttributeDict()
volume_a = structure_a.get_cell_volume()
volume_b = structure_b.get_cell_volume()
delta.absolute.volume = np.absolute(volume_a - volume_b)
delta.relative.volume = np.absolute(volume_a - volume_b) / volume_a
pos_a = np.array([site.position for site in structure_a.sites])
pos_b = np.array([site.position for site in structure_b.sites])
delta.absolute.pos = pos_a - pos_b
site_vectors = [delta.absolute.pos[i, :] for i in range(delta.absolute.pos.shape[0])]
a_lengths = np.linalg.norm(pos_a, axis=1)
delta.absolute.pos_lengths = np.array([np.linalg.norm(vector) for vector in site_vectors])
delta.relative.pos_lengths = np.array([np.linalg.norm(vector) for vector in site_vectors]) / a_lengths
cell_lengths_a = np.array(structure_a.cell_lengths)
delta.absolute.cell_lengths = np.absolute(cell_lengths_a - np.array(structure_b.cell_lengths))
delta.relative.cell_lengths = np.absolute(cell_lengths_a - np.array(structure_b.cell_lengths)) / cell_lengths_a
cell_angles_a = np.array(structure_a.cell_angles)
delta.absolute.cell_angles = np.absolute(cell_angles_a - np.array(structure_b.cell_angles))
delta.relative.cell_angles = np.absolute(cell_angles_a - np.array(structure_b.cell_angles)) / cell_angles_a
return delta
[docs]
def fetch_k_grid(rec_cell, k_spacing):
"""
Suggest a sensible k-point sampling based on a supplied spacing.
:param rec_cell: A two dimensional ndarray of floats defining the reciprocal lattice with each vector as row elements.
:param k_spacing: The k-point spacing.
:return kgrid: The k-point grid given the supplied `rec_cell` and `kstep`
This is usable for instance when performing
plane wave cutoff convergence tests without a base k-point grid.
"""
rec_cell_lenghts = np.linalg.norm(rec_cell, axis=1)
kgrid = np.ceil(rec_cell_lenghts / np.float64(k_spacing))
return kgrid.astype('int').tolist()
[docs]
def compose_exit_code(status, message):
"""Compose an ExitCode instance based on a status and message."""
exit_code = ExitCode(status=status, message=message)
return exit_code
[docs]
def site_magnetization_to_magmom(site_dict):
"""
Convert site magnetization to MAGMOM used for restart
NOTE: Only tested for colinear cases
"""
if 'site_magnetization' in site_dict:
site_dict = site_dict['site_magnetization']
site_dict = site_dict['sphere']
to_use = None
for symbol in 'xyz':
if site_dict.get(symbol) and site_dict.get(symbol, {}).get('site_moment'):
to_use = symbol
break
# No available site magnetization for setting MAGMOM, something is wrong
if to_use is None:
raise ValueError('No valid site-projected magnetization available')
# Ensure sorted list
tmp = list(site_dict[to_use]['site_moment'].items())
tmp.sort(key=lambda x: int(x[0]))
return [entry[1]['tot'] for entry in tmp]