def ase_atom_my_atom(ase_data): lattice = [] for vector in ase_data.cell: lattice.append(tuple(vector)) # ASE converts basis to cartesian, so convert back inv_lattice = np.linalg.inv(np.transpose(np.asarray(ase_data.cell))) basis = [] for pos in ase_data.positions: frac_pos = np.matmul(inv_lattice, pos) basis.append(tuple(frac_pos)) atomic_numbers = [] for an in ase_data.numbers: atomic_numbers.append(an) # an_to_symbol = atomic_number_symbol_dict() n_atoms = len(atomic_numbers) molecule = [] for ia in range(0, n_atoms): species = an_to_symbol[atomic_numbers[ia]] molecule.append(atoms.Atom(species, basis[ia])) return molecule
def super_cell_from_crystal(rutile: dict, cell_integers: list) -> dict: assert rutile['lattice_parameters']['a'].unit == 'angstrom' # Extract data a = rutile['lattice_parameters']['a'].value c = rutile['lattice_parameters']['c'].value lattice = bravais.simple_tetragonal(a, c) positions_angstrom = [ np.matmul(lattice, pos) for pos in rutile['fractional'] ] species = rutile['species'] # Compute supercell unit_cell = [ atoms.Atom(species[ia], positions_angstrom[ia]) for ia in range(0, len(species)) ] super_cell = supercell.build_supercell( unit_cell, supercell.translation_vectors(lattice, cell_integers)) assert len(super_cell) == np.prod(cell_integers) * len(unit_cell) lattice_scell = supercell.get_supercell_vector(lattice, cell_integers) #write.xyz('rutile_222.xyz', super_cell) # Repackage the information inv_lattice_scell = np.linalg.inv(lattice_scell) positions_frac = [ np.matmul(inv_lattice_scell, atom.position) for atom in super_cell ] species_sc = [atom.species for atom in super_cell] a = np.linalg.norm(lattice_scell[:, 0]) c = np.linalg.norm(lattice_scell[:, 2]) lattice_parameters = {'a': Set(a, 'angstrom'), 'c': Set(c, 'angstrom')} data = { 'fractional': positions_frac, 'species': species_sc, 'lattice_parameters': lattice_parameters, 'space_group': ('', 136), #rutile['space_group'] 'n_atoms': len(species_sc) } return data
def replace_loose_atoms(unit_cell: list, loose_atom_indices: List[int], equivalent_positions: list, visualise_parts=False) -> list: """ Remove uncoordinated atoms and their equivalents to the unit cell :param unit_cell: List of atoms :param loose_atom_indices: Indices for uncoordinated atoms :param equivalent_positions: List of equivalent positions for uncoordinated atoms. of size len(loose_atom_indices) :param visualise_parts: bool, output .xyz of original unit_cell, removed atoms and replacement atoms :return new_unit_cell with no uncoordinated atoms """ assert len(loose_atom_indices) == len(equivalent_positions), "Should be one new (equivalent) " \ "position per uncoordinated atom" # Can't use pop as it changes the indexing each time new_unit_cell = [] removed_atoms = [] for ia in range(0, len(unit_cell)): if ia not in loose_atom_indices: new_unit_cell.append(unit_cell[ia]) else: removed_atoms.append(unit_cell[ia]) #TODO(Alex) Generalise # I know they're all oxygens but should treat this correctly if making general replacements = [ atoms.Atom(position=position, species='O') for position in equivalent_positions ] if visualise_parts: output_dir = 'aei_outputs' xyz(output_dir + '/' + "aei_central_cell", unit_cell) xyz(output_dir + '/' + "aei_replacements_cell", replacements) xyz(output_dir + '/' + "aei_removed_atoms", removed_atoms) return new_unit_cell + replacements
from modules.electronic_structure.structure import atoms, bravais, crystals, supercell from modules.electronic_structure.basis import gfn1 from modules.parameters import crystals as params from modules.fileio import write from modules import entos # Silicon cubic unit cell in angstrom al = params.silicon['lattice_constant']['angstrom'] fractional_basis_positions = crystals.silicon('conventional') lattice = bravais.simple_cubic(al) unit_cell = [] for atom in fractional_basis_positions: pos_angstrom = np.matmul(lattice, atom.position) unit_cell.append(atoms.Atom(atom.species, pos_angstrom)) def silicon_supercell(n, centred_on_zero=None): if centred_on_zero == None: centred_on_zero = (n[0] * n[1] * n[2]) % 2 != 0 translations = supercell.translation_vectors( lattice, n, centred_on_zero=centred_on_zero) super_cell = supercell.build_supercell(unit_cell, translations) # Information print('Number of atoms in supercell:', len(super_cell)) # Find central cell icentre = supercell.flatten_supercell_limits(
def triangle_from(tetrahedron): # Separate silicons and oxygens triangle = [] silicon = [] for atom in tetrahedron: if atom.species.lower() == 'si': silicon.append(atom) elif atom.species.lower() == 'o': triangle.append(atom) assert len( triangle ) == 3, "triangle_from function expects tetrahedron containing 3 oxygen" assert len( silicon ) == 1, "triangle_from function expects tetrahedron containing 1 silicon" # Define 2 of 3 vertices that form the oxygen triangle v01 = triangle[1].position - triangle[0].position v12 = triangle[2].position - triangle[1].position # Normal to triangle surface normal = np.cross(v01, v12) unit_normal = normal / np.linalg.norm(normal) #print(normal, unit_normal) # Silicon - oxygen distances si_o_0 = np.linalg.norm(silicon[0].position - triangle[0].position) si_o_1 = np.linalg.norm(silicon[0].position - triangle[1].position) si_o_2 = np.linalg.norm(silicon[0].position - triangle[2].position) # Silicon atom is above the plane and one needs to reverse the norm if np.dot(silicon[0].position - triangle[0].position, unit_normal) > 1: unit_normal = -unit_normal # Progagate si incrementally along unit normal, until distances from all oxy are minimised bond_length = si_o_0 si_0 = np.asarray(silicon[0].position) print("bond_length", bond_length) # Alt way of stepping # sep = 1000 # pos = np.zeros(shape=(3)) # for dr in np.linspace(0, bond_length, sep): # ang step = 0.001 * bond_length pos = np.zeros(shape=(3)) for dr in np.arange(0 + step, bond_length + step, step): pos += si_0 + (dr * unit_normal) # print("pos,",pos) # print(np.linalg.norm(pos - triangle[0].position), \ # np.linalg.norm(pos - triangle[1].position), \ # np.linalg.norm(pos - triangle[2].position)) # print(si_o_0, si_o_1, si_o_2) if (np.linalg.norm(pos - triangle[0].position) <= si_o_0) and \ (np.linalg.norm(pos - triangle[1].position) <= si_o_1) and \ (np.linalg.norm(pos - triangle[2].position) <= si_o_2): si_o_0 = np.linalg.norm(pos - triangle[1].position) si_o_1 = np.linalg.norm(pos - triangle[1].position) si_o_2 = np.linalg.norm(pos - triangle[2].position) final_pos = pos else: break triangle.append(atoms.Atom('B', final_pos)) return triangle
import numpy as np import random from modules.electronic_structure.structure import atoms, bravais # Central silicon with 4 surrounding oxygen al = 7.12637 molecule = [ atoms.Atom('si', al * np.array([0, 0, 0])), atoms.Atom('o', al * np.array([0.25, 0.25, 0.25])), atoms.Atom('o', al * np.array([0.25, -0.25, -0.25])), atoms.Atom('o', al * np.array([-0.25, 0.25, -0.25])), atoms.Atom('o', al * np.array([-0.25, -0.25, 0.25])) ] # Test tetrahedron to triangle operation #triangle = operations.triangle_from(molecule) #write.xyz("triangle", triangle) # For a given tetrahedron, remove one oxygen at random # and move the silicon into the plane of the remaining 3 atoms # #for each step, store norm(atom0_si - atom1), norm(atom0_si - atom2) and norm(atom0_si - atom3) #these should get smaller. Once they start getting larger, stop. atom_si is now in the plane. # Maybe a more mathematical way of doing it but should be quite fast # # Make more robust to deal with fractional or angstrom # def triangle_from(tetrahedron):
import numpy as np from modules.electronic_structure.structure import atoms, bravais, crystals, supercell from modules.electronic_structure.basis import gfn1 from modules.parameters import crystals as params from modules.fileio import write # Silicon dioxide cubic primitive unit cell. Could be wrong but doesn't matter, just want two atom types fractional_basis_positions = [ atoms.Atom('Si', [0, 0, 0]), atoms.Atom('O', [0.25, 0.25, 0.25]) ] lattice = bravais.face_centred_cubic(1.) unit_cell = [] for atom in fractional_basis_positions: pos_angstrom = np.matmul(lattice, atom.position) unit_cell.append(atoms.Atom(atom.species, pos_angstrom)) # Supercell # If odd, can centre on T=(0,0,0), else can't n = [3, 3, 3] translations = supercell.translation_vectors(lattice, n, centred_on_zero=True) super_cell = supercell.build_supercell(unit_cell, translations) # Central cell icentre = supercell.flatten_supercell_limits([0, 0, 0], n, centred_on_zero=True) cells = supercell.list_global_atom_indices_per_cells(unit_cell, translations)
import numpy as np from modules.fileio import read from modules.electronic_structure.structure import atoms import read_basis # Molecule: Positions in angstrom at this point names, positions = read.xyz("molecules/pyridine.xyz") molecule = [] for iatom in range(0, len(names)): position = positions[iatom] molecule.append(atoms.Atom(names[iatom], position)) # Basis sets: https://www.basissetexchange.org read_basis.sto_3g("basis_sets/STO-3G/sto-3g.1-2.json") # Integrals # Symmetric orthogonalisation of the basis # SCF