Source code for httk.external.pymatgen_glue

#
#    The high-throughput toolkit (httk)
#    Copyright (C) 2012-2015 Rickard Armiento
#
#    This program is free software: you can redistribute it and/or modify
#    it under the terms of the GNU Affero General Public License as
#    published by the Free Software Foundation, either version 3 of the
#    License, or (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU Affero General Public License for more details.
#
#    You should have received a copy of the GNU Affero General Public License
#    along with this program.  If not, see <http://www.gnu.org/licenses/>.

import os

from httk.core import citation
from httk.core.basic import is_sequence
citation.add_ext_citation("Pymatgen",
                          "Shyue Ping Ong, William Davidson Richards, Anubhav Jain, Geoffroy Hautier, Michael Kocher, \
Shreyas Cholia, Dan Gunter, Vincent Chevrier, Kristin A. Persson, Gerbrand Ceder. \
Python Materials Genomics (pymatgen) : A Robust, Open-Source Python Library for Materials Analysis. \
Computational Materials Science, 2013, 68, 314-319. \
doi:10.1016/j.commatsci.2012.10.028; and others")
import httk.atomistic.data
from httk.core.httkobject import HttkPlugin, HttkPluginWrapper

from httk import config
from httk.atomistic import Structure, UnitcellSites, Spacegroup
from httk.core.vectors import FracVector

from httk.atomistic import Structure, UnitcellSites
import httk.iface
from httk.external.subimport import submodule_import_external

pymatgen_major_version = None
pymatgen_minor_version = None

try:
    pymatgen_path = config.get('paths', 'pymatgen')
except Exception:
    pymatgen_path = None

    try:
        import pymatgen

        try:
            from importlib.metadata import version
            en_major_version = version('pymatgen')
            pymatgen_minor_version = ""
        except AttributeError:
            pymatgen_major_version = pymatgen.__version__.split('.')[0]
            pymatgen_minor_version = pymatgen.__version__.split('.')[1]

    except ImportError:
        pass

mp_key = ""

[docs] def set_mp_key(key): global mp_key mp_key = key
[docs] def ensure_pymatgen_is_imported(): if pymatgen_path == "False": raise Exception("httk.external.pymatgen_glue: module pymatgen_glue imported, but pymatgen is disabled in configuration file.") if pymatgen_major_version is None: raise ImportError("httk.external.pymatgen_glue imported without access to the pymatgen python library.")
if pymatgen_path != "False": if pymatgen_path is not None: submodule_import_external(os.path.join(pymatgen_path), 'pymatgen') else: try: external = config.get('general', 'allow_system_libs') except Exception: external = 'yes'
[docs] def structure_to_pmg_struct(struct): """Converts httk structures to Pymatgen structures.""" from httk.external.pymatgen_ext import pymatgen basis = struct.uc_basis.to_floats() coords = struct.uc_reduced_coords.to_floats() counts = struct.uc_counts species = [] for a, count in zip(struct.assignments, counts): for _ in range(count): species.append(a.symbols[0]) try: return pymatgen.Structure(basis, species, coords) except AttributeError: return pymatgen.core.Structure(basis, species, coords)
[docs] def pmg_struct_to_spglib_tuple(pmg_struct, return_atomic_symbols=False): cell = pmg_struct.lattice.matrix.tolist() coords = pmg_struct.frac_coords.tolist() # There is no direct way to get a list of symbols? atomic_symbols = [] symbols_int = [] for s in pmg_struct.species: atomic_symbols.append(s.value) symbols_int.append(s.number) if return_atomic_symbols: return (cell, coords, symbols_int), atomic_symbols else: return (cell, coords, symbols_int)
[docs] def pmg_struct_to_structure(pmg_struct, hall_symbol=None, comment=None, find_primitive=False): """Converts Pymatgen structures to httk structures. The correct Hall symbol can be optionally determined. The POSCAR comment line can also be given. Structure can be optionally reduced to the standard conventional structure, which also gives the standard primitive structure (struct.pc). """ (cell, coords, symbols_int), atomic_symbols = pmg_struct_to_spglib_tuple(pmg_struct, return_atomic_symbols=True) if find_primitive: from httk.external.numpy_ext import numpy as np from httk.external.pyspglib_ext import spglib dataset = spglib.get_symmetry_dataset( (cell, coords, symbols_int)) hall_symbol = dataset['hall'] spacegroupnumber = dataset['number'] spacegroup = Spacegroup.create(hall_symbol=hall_symbol, spacegroupnumber=spacegroupnumber) rc_reduced_occupationscoords = [] rc_occupancies = [] multiplicities = [] wyckoff_symbols = [] rc_basis = dataset['std_lattice'].tolist() rc_pos = dataset['std_positions'].tolist() for ind in set(dataset['equivalent_atoms']): atom = symbols_int[ind] equiv_orbs_where = np.argwhere(dataset['equivalent_atoms'] == ind).flatten() prim_index = dataset['mapping_to_primitive'][ind] std_index = int(np.argwhere(dataset['std_mapping_to_primitive'] == prim_index).flatten()[0]) rc_reduced_occupationscoords.append(rc_pos[std_index]) rc_occupancies.append({'atom': atom, 'ratio': FracVector(1, 1)}) multiplicities.append(len(equiv_orbs_where)) wyckoff_symbols.append(dataset['wyckoffs'][ind]) # Multiplicities have to be "normalized" if the input cell was a supercell # containing multiple primitive/standard conventional cells, or if # the input cell was the primitive unit cell, i.e. smaller than the # conventional cell. if sum(multiplicities) > len(dataset['std_mapping_to_primitive']): assert sum(multiplicities) % len(dataset['std_mapping_to_primitive']) == 0 multiplier = sum(multiplicities) // len(dataset['std_mapping_to_primitive']) for i in range(len(multiplicities)): multiplicities[i] //= multiplier elif sum(multiplicities) < len(dataset['std_mapping_to_primitive']): assert len(dataset['std_mapping_to_primitive']) % sum(multiplicities) == 0 multiplier = len(dataset['std_mapping_to_primitive']) // sum(multiplicities) for i in range(len(multiplicities)): multiplicities[i] *= multiplier assert sum(multiplicities) == len(dataset['std_mapping_to_primitive']) struct = Structure.create( spacegroup=spacegroup, rc_basis=rc_basis, rc_reduced_occupationscoords=rc_reduced_occupationscoords, rc_occupancies=rc_occupancies, wyckoff_symbols=wyckoff_symbols, multiplicities=multiplicities, ) elif hall_symbol == 'generate': from httk.external.pyspglib_ext import spglib dataset = spglib.get_symmetry_dataset( (cell, coords, symbols_int)) hall_symbol = dataset['hall'] spacegroupnumber = dataset['number'] spacegroup = Spacegroup.create(hall_symbol=hall_symbol, spacegroupnumber=spacegroupnumber) struct = Structure.create(rc_basis=cell, rc_occupancies=atomic_symbols, rc_reduced_occupationscoords=coords, periodicity=[1, 1, 1], spacegroup=spacegroup) elif hall_symbol is None: spacegroup = Spacegroup.create(hall_symbol="P 1", spacegroupnumber=1) struct = Structure.create(rc_basis=cell, rc_occupancies=atomic_symbols, rc_reduced_occupationscoords=coords, periodicity=[1, 1, 1], spacegroup=spacegroup) else: struct = Structure.create(rc_basis=cell, rc_occupancies=atomic_symbols, rc_reduced_occupationscoords=coords, periodicity=[1, 1, 1], hall_symbol=hall_symbol) if comment is not None: struct.add_tag('comment', comment) return struct