Source code for strawberrypy.utils

r"""A module containing utility functions for internal use that are not related to Models specifically."""

import numpy as np


[docs] def unique_vacancies( num: int, Lx: int, Ly: int, basis: int, atom_type: int = None, same_number: bool = False, seed: int = None, ): r"""Returns a list of unique random lattice sites to be removed in the model using the method :meth:`~strawberrypy.Model.add_vacancies`. Parameters ---------- num : Number of lattice positions to generate. Lx : Number of unit cells of the model along the :math:`\mathbf{a}_1` direction. Ly : Number of unit cells of the model along the :math:`\mathbf{a}_2` direction. basis : Number of atoms per unit cell. atom_type : Index of the atom to be removed. same_number : If :python:`True`, the same number of each type of atom is removed. seed : Seed for the random number generation. Default is :python:`None`. Returns ------- unique_list : :python:`list` List of unique random lattice site. """ indexes = [] unique_list = [] # Set random seed if seed is not None: np.random.seed(seed) # Check if atom_type is valid if atom_type is not None and (atom_type < 0 or atom_type >= basis): raise ValueError(f"atom_type must be between 0 and {basis - 1}") if same_number: atom = np.zeros(num, dtype=np.uint32) type_B = np.zeros(num, dtype=np.uint32) type_B[: num // basis] = np.ones(num // basis, dtype=np.uint32) nonzeros = np.sort(np.nonzero(np.random.permutation(type_B))[0]) atom[nonzeros] = np.ones(num // basis, dtype=np.uint32) ind = 0 # Generate num unique entries while len(unique_list) < num: # Trial entry at_type = int(atom[ind]) trial = [np.random.randint(Lx), np.random.randint(Ly), at_type] # Generate internal index trial_index = Ly * basis * trial[0] + basis * trial[1] + trial[2] # If this is a new entry store it if trial_index not in indexes: indexes.append(trial_index) unique_list.append(trial) ind += 1 else: # Generate num unique entries while len(unique_list) < num: # Trial entry if atom_type is not None: trial = [np.random.randint(Lx), np.random.randint(Ly), atom_type] else: trial = [ np.random.randint(Lx), np.random.randint(Ly), np.random.randint(basis), ] # Generate internal index trial_index = Ly * basis * trial[0] + basis * trial[1] + trial[2] # If this is a new entry store it if trial_index not in indexes: indexes.append(trial_index) unique_list.append(trial) return unique_list
def _create_orb_pattern(orb_pos: list[list[float]]) -> list[int]: r"""Creates a pattern list that assigns the same index (starting from 0) to orbitals that occupy the same position within the unit cell, within a specified tolerance. Parameters ---------- orb_pos : list of list of float A list of orbital positions, where each position is a list of three floats representing the (x, y, z) coordinates of the orbital within the unit cell. Returns ------- pattern : list of int A list of integers where each integer corresponds to the index of the unique position that the orbital occupies. Orbitals that occupy the same position (within the specified tolerance) will have the same index. Examples ------- >>> orb_pos = [[0.0, 0.0], [0.00, 0.], [0.123, 0.24], [0.23, 0.25], [0.230, 0.250]] >>> _create_orb_pattern(orb_pos) [0, 0, 1, 2, 2] """ tolerance = 1e-7 pattern = [] unique_points = [] counter = 0 for pos in orb_pos: found = False for i, upos in enumerate(unique_points): # Compare both coordinates with tolerance if ( abs(pos[0] - upos[0]) < tolerance and abs(pos[1] - upos[1]) < tolerance and abs(pos[2] - upos[2]) < tolerance ): pattern.append(i) found = True break if not found: unique_points.append(pos) pattern.append(counter) counter += 1 return pattern