Source code for gflownet.utils.crystals.pyxtal_cache

import numpy
from pyxtal.symmetry import Group

_pyxtal_space_group_cache = {}
_pyxtal_check_compatible_cache = {}
_pyxtal_space_group_free_wp_multiplicity = {}
_pyxtal_space_group_wp_lowest_common_factor = {}


[docs] def get_space_group(group_index): """ Returns a PyxTal Group object representing a crystal space group This methods includes a lazy caching mechanism since the instantiation of a pyxtal.symmetry.Group object is expensive. Args ---- group_index : int Index (starting at 1) of the space group Returns ------- pyxtal.symmetry.Group Requested space group """ if group_index not in _pyxtal_space_group_cache: _pyxtal_space_group_cache[group_index] = Group(group_index) return _pyxtal_space_group_cache[group_index]
[docs] def space_group_check_compatible(group_index, composition): """ Determines if a given atom composition is compatible with a space group This methods internally relies on pyxtal.symmetry.Group.check_compatible() to determine if a composition and a space group are compatible but this method includes a caching mechanism since the call to check_compatible() is expensive. Args ---- group_index : int Index (starting at 1) of the space group composition : list of ints Atom composition. Each element in the list corresponds to the number of atoms of a distinct element in the crystal conventional cell Returns ------- is_compatible : bool True if the composition and space group are compatible. False otherwise. """ # Remove from composition the number of atoms that are a multiple of the # space group's most specific free wyckoff position. This improves the # cache hit rate without affecting the validity of the composition free_multiplicity = space_group_lowest_free_wp_multiplicity(group_index) composition = [c for c in composition if c % free_multiplicity != 0] # Get a tuple version of composition to ensure immutability and, # therefore, allow dictionary indexing by composition. Ensure the elements # in the tuple are sorted to improve cache hit rate since it doesn't # affect the validity of a composition t_composition = tuple(sorted(composition)) # Check in the cache to see if PyxTal has previously been called to # validate this space group and composition if group_index in _pyxtal_check_compatible_cache: if t_composition in _pyxtal_check_compatible_cache[group_index]: return _pyxtal_check_compatible_cache[group_index][t_composition] else: _pyxtal_check_compatible_cache[group_index] = {} # Obtain the space group object space_group = get_space_group(group_index) # Perform compatibility check is_compatible = space_group.check_compatible(composition)[0] # Store result in cache before returning it _pyxtal_check_compatible_cache[group_index][t_composition] = is_compatible return is_compatible
[docs] def space_group_lowest_free_wp_multiplicity(group_index): """ Returns the multiplicity of a space group's most specific free WP. This methods includes a lazy caching mechanism since the call to PyXtal methods to determine if a Wyckoff position is fixed or free is expensive. Args ---- group_index : int Index (starting at 1) of the space group Returns ------- multiplicity : int Multiplicity of the most specific free wyckoff position. """ # Check in the cache to see if the multiplicity has previously been # computed for this space group if group_index in _pyxtal_space_group_free_wp_multiplicity: return _pyxtal_space_group_free_wp_multiplicity[group_index] # Obtain reference to the space group space_group = get_space_group(group_index) # Iterate over all of the space group's wyckoff positions from most # specific to most general until a wyckoff position with a degree of # freedom is found. multiplicity = None for wyckoff_idx in range(1, len(space_group.wyckoffs) + 1): wyckoff_position = space_group.get_wyckoff_position(-wyckoff_idx) if wyckoff_position.get_dof() > 0: multiplicity = wyckoff_position.multiplicity break # Store the result in cache before retuning it _pyxtal_space_group_free_wp_multiplicity[group_index] = multiplicity return multiplicity
[docs] def space_group_wyckoff_gcd(group_index): """ Returns the greatest common divisor of a space group's Wyckoff positions This methods includes a lazy caching mechanism. Args ---- group_index : int Index (starting at 1) of the space group Returns ------- gcd : int Greatest common divisor of the group's wyckoff position. """ # Check in the cache to see if the lowest common factor has previously # been computed for this space group if group_index in _pyxtal_space_group_wp_lowest_common_factor: return _pyxtal_space_group_wp_lowest_common_factor[group_index] # Obtain reference to the space group space_group = get_space_group(group_index) # Iterate over all of the space group's wyckoff positions from most # specific to most general until a wyckoff position with a degree of # freedom is found. multiplicities = [] for wyckoff_idx in range(0, len(space_group.wyckoffs)): wyckoff_position = space_group.get_wyckoff_position(wyckoff_idx) multiplicities.append(wyckoff_position.multiplicity) gcd = numpy.gcd.reduce(multiplicities) # Store the result in cache before retuning it _pyxtal_space_group_wp_lowest_common_factor[group_index] = gcd return gcd