def moleculr_from_indices(species, positions, atomic_indices): new_species = [] new_positions = [] for ia in atomic_indices: new_species.append(species[ia]) new_positions.append(positions[ia]) return atoms.Atoms(new_species, new_positions)
def rhomohedral(): system_label = 'rhom_mos' a = 12.96 alpha = 0.470 lattice = bravais.rhombohedral(a, alpha, 'rhom') fractional_positions = np.array([[0.000007, 0.000007, 0.000007], [0.254176, 0.254176, 0.254176], [0.412458, 0.412458, 0.412458]]).transpose() positions = np.matmul(lattice, fractional_positions).transpose() unit_cell = atoms.Atoms(['Mo', 'S', 'S'], positions.tolist()) return System(system_label, unit_cell, lattice)
def hexagonal(): system_label = 'hex_bn' a = 4.75 c = 14.56 lattice = bravais.hexagonal(a, c) fractional_positions = np.array([[0.333333, 0.666667, 0.250000], [0.666667, 0.333333, 0.750000], [0.333333, 0.666667, 0.750000], [0.666667, 0.333333, 0.250000]]).transpose() positions = np.matmul(lattice, fractional_positions).transpose() unit_cell = atoms.Atoms(['B', 'B', 'N', 'N'], positions.tolist()) return System(system_label, unit_cell, lattice)
def simple_orthorhombic(): system_label = 'simple_orth_cdau' a = 5.83 b = 9.30 c = 9.74 lattice = bravais.simple_orthorhombic(a, b, c) fractional_positions = np.array([[0.00000000, 0.75000000, 0.69415500], [0.00000000, 0.25000000, 0.30584500], [0.50000000, 0.75000000, 0.18925900], [0.50000000, 0.25000000, 0.81074100]]).transpose() positions = np.matmul(lattice, fractional_positions).transpose() unit_cell = atoms.Atoms(['Cd', 'Cd', 'Au', 'Au'], positions.tolist()) return System(system_label, unit_cell, lattice)
def simple_cubic(): system_label = 'cubic_silicon' al = 10.33 species = ['Si'] * 8 positions = al * np.array([[0.25000000, 0.75000000, 0.25000000], [0.00000000, 0.00000000, 0.50000000], [0.25000000, 0.25000000, 0.75000000], [0.00000000, 0.50000000, 0.00000000], [0.75000000, 0.75000000, 0.75000000], [0.50000000, 0.00000000, 0.00000000], [0.75000000, 0.25000000, 0.25000000], [0.50000000, 0.50000000, 0.50000000]]) unit_cell = atoms.Atoms(species, positions) lattice = bravais.simple_cubic(al) return System(system_label, unit_cell, lattice)
def simple_tetragonal(): system_label = 'simple_tet_tio2' a = 8.71 c = 5.65 lattice = bravais.simple_tetragonal(a, c) fractional_positions = np.array([[0.000000, 0.000000, 0.000000], [0.500000, 0.500000, 0.500000], [0.695526, 0.695526, 0.000000], [0.304474, 0.304474, 0.000000], [0.195526, 0.804474, 0.500000], [0.804474, 0.195526, 0.500000]]).transpose() positions = np.matmul(lattice, fractional_positions).transpose() unit_cell = atoms.Atoms(['Ti', 'Ti', 'O', 'O', 'O', 'O'], positions.tolist()) return System(system_label, unit_cell, lattice)
def get_primitive_unit_cell(directories: Directories, visualise=False): """ Wrapper for reading CIF file, converting it to a primitive unit cell and returning it in data structure, along with lattice vectors :param directories: Structure, input and output strings :param visualise: Output structure as .xyz :return: unit_cell, lattice_vectors: Unit cell and lattice vectors """ structure_name = directories.structure input_dir = directories.input output_dir = directories.output ase_input_data = ase.io.read(input_dir + "/" + structure_name + ".cif", store_tags=False) spg_input = ase_to_spglib(ase_input_data) print("Number of atoms in input", len(spg_input[2])) # Reduce to primitive with SPG #print("Find primitive of conventional structure") lattice, positions, numbers = spglib.find_primitive(spg_input, symprec=1e-5) if visualise: spg_molecule = (lattice, positions, numbers) #spg_show_cell(lattice, positions, numbers) spg_write(output_dir + '/' + structure_name + '_primitive_cell.xyz', spg_molecule, pbc=(1, 1, 1)) # Need lattice vectors column-wise, in np array lattice_vectors = np.zeros(shape=(3, 3)) for i in range(0, 3): lattice_vectors[:, i] = lattice[i] # Need positions in angstrom, not fractional positions_ang = [] for position in positions: positions_ang.append(np.matmul(lattice, position)) # Need unit cell in my molecule format species = [an_to_symbol[an] for an in numbers] unit_cell = atoms.Atoms(species=species, positions=positions_ang) return unit_cell, lattice_vectors
def simple_monoclinic(): system_label = 'simpe_mono_lisn' a = 9.79 b = 6.09 c = 14.75 beta = 1.85 lattice = bravais.simple_monoclinic(a, b, c, beta) fractional_positions = np.array([[0.268026, 0.500000, 0.331701], [0.500000, 0.500000, 0.000000], [0.731974, 0.500000, 0.668299], [0.241273, 0.000000, 0.661946], [0.758727, 0.000000, 0.338054], [0.000000, 0.000000, 0.000000]]).transpose() positions = np.matmul(lattice, fractional_positions).transpose() unit_cell = atoms.Atoms(['Li', 'Li', 'Li', 'Sn', 'Sn', 'Sn'], positions.tolist()) return System(system_label, unit_cell, lattice)
def fcc(): system_label = 'fcc_silicon' al = 10.26 unit_cell = atoms.Atoms(['Si', 'Si'], [[0, 0, 0], [0.25 * al] * 3]) lattice = bravais.face_centred_cubic(al) return System(system_label, unit_cell, lattice)
def bcc(): system_label = 'bcc_potassium' al = 8.612 unit_cell = atoms.Atoms(['K'], [[0, 0, 0]]) lattice = bravais.body_centred_cubic(al) return System(system_label, unit_cell, lattice)
def ring_substitutions(aei_ring_unit): """ :brief :result """ assert isinstance(aei_ring_unit, list), \ "aei_ring_unit should be list[atoms.Atom]" assert isinstance(aei_ring_unit[0], atoms.Atom), \ "aei_ring_unit should be list[atoms.Atom]" species = [atom.species for atom in aei_ring_unit] positions = [atom.position for atom in aei_ring_unit] new_species, new_positions = convert_ring(species, positions) return atoms.Atoms(new_species, new_positions) # # Simple hack as I know the structure beforehand # # If in the correct spatial region and is bonded (could remove the 2nd assertion) # def ring_indices(unit_cell, in_ring): # # positions = [atom.position for atom in unit_cell] # d = spatial.distance_matrix(positions, positions) # max_bond_length = 1.7 # # indices = [] # for ia in range(0, len(unit_cell)): # if in_ring(positions[ia]): # neighbours = np.where((d[ia, :] > 0.) & (d[ia, :] <= max_bond_length))[0] # if len(neighbours) > 0: # indices.append(ia) # return indices # # # def get_ring(ring_indices, unit_cell): # species = [] # positions = [] # for i in ring_indices: # species.append(unit_cell[i].species) # positions.append(unit_cell[i].position) # return species, positions # # # def swap_ring(ring_indices, unit_cell): # species, positions = get_ring(ring_indices, unit_cell) # # write.xyz("extracted_ring.xyz", atoms.Atoms(species, positions)) # new_species, new_positions = convert_ring(species, positions) # converted_ring = atoms.Atoms(new_species, new_positions) # # # New structure, with old ring swapped out for the new # unit_cell_minus_ring = [] # for i, atom in enumerate(unit_cell): # if i not in ring_indices: # unit_cell_minus_ring.append(atom) # # return unit_cell_minus_ring + converted_ring # # # ------------------- # Main routine # ------------------- # Read in CIF and convert to primitive cell # directories = cell_operations.Directories(structure='aei', # input='inputs', # output='aei_outputs') # # unit_cell, lattice_vectors = cell_operations.get_primitive_unit_cell(directories) # translations = cell_operations.translations_for_fully_coordinated_unit(unit_cell, lattice_vectors) # coordinating_atoms = cell_operations.find_atoms_neighbouring_central_cell( # unit_cell, translations) # # # Breaks the ring routine if I add coordinating_atoms here # #unit_cell = unit_cell + coordinating_atoms # # # For AEI primitive cell, the rings are: # # Every connected atom above x value of 11.52979 # # Every connected atom below an x value of 7 # top_ring_indices = ring_indices(unit_cell, lambda pos: pos[0] > 11.5) # # structure = swap_ring(top_ring_indices, unit_cell) # bottom_ring_indices = ring_indices(structure, lambda pos: pos[0] <= 7) # structure = swap_ring(bottom_ring_indices, structure) # # write.xyz("new_ring.xyz", structure) # def ring_test(): # species, positions = read.xyz("inputs/ring.xyz") # new_species, new_positions = convert_ring(species, positions) # molecule = atoms.Atoms(new_species, new_positions) # write.xyz("one_unit.xyz", molecule) # # quit() # # first_boron_index = next(i for i,symbol in enumerate(new_species) if symbol == 'B') # # #TODO(Alex) This doesn't work properly # # Find 2nd-shortest B-B bond length. # n_atoms = len(new_species) # boron_indices = [i for i in range(0, n_atoms) if new_species[i] == 'B'] # new_positions = np.asarray(new_positions) # new_species = np.asarray(new_species) # boron_positions = new_positions[boron_indices] # d_boron = spatial.distance_matrix(boron_positions, boron_positions) # molecule = atoms.Atoms(new_species[boron_indices], boron_positions) # write.xyz("borons.xyz", molecule) # # # This gets lucky # second_shortest_distance = np.sort(d_boron[0,:])[2] # # # Create list of pairs # boron_pairs = [] # for i in range(0, len(boron_indices)): # j = np.where(d_boron[i,:] == second_shortest_distance) # print(j) # boron_pairs.append([i,j]) # # # Put oxygens between these boron pairs # # # molecule = atoms.Atoms(new_species, new_positions) # write.xyz("one_unit.xyz", molecule) # # # # # TODO(Alex) # # Deal with si-o-o and, potentially # # Need to write something to identify the rings in the primitive cell: Just list manually. # # # # # quit() # # Move each atom out along vector with ring centre # l = 5 # new_positions = [] # for ia in range(0, len(species)): # position = positions[ia] # # Point outwards from the centre # radial_vector = np.asarray(position) - ring_centre # unit_radial_vector = radial_vector / np.linalg.norm(radial_vector) # scaled_radial_vector = l * unit_radial_vector # assert( np.isclose(np.linalg.norm(scaled_radial_vector), l) ) # new_positions.append(scaled_radial_vector + position) # # molecule = atoms.Atoms(species, new_positions) # write.xyz("test.xyz", molecule)
def convert_ring(species, positions): n_atoms = len(species) ring_centre = geometry.find_centre(positions) si_oo_units, oxy_ring_atoms = identify_si_o_o_units(species, positions, plane_index=0) # Else same atom will get shifted for each time it reappears in a unit si_oo_units = remove_sharing_oxygens(si_oo_units) # Move each si_oo_unit, length found from trial and error (specific to AEI) length = 8 for unit in si_oo_units: # Find unit centre unit_centre = geometry.find_centre( [positions[iatom] for iatom in unit]) # Point outwards from the ring centre radial_vector = np.asarray(unit_centre) - ring_centre scaled_radial_vector = scaled_vector(length, radial_vector) # Update each position for atom in unit: positions[atom] = scaled_radial_vector + positions[atom] # Move each oxy atom in the ring oxy_ring_positions = move_atoms_radially(oxy_ring_atoms, positions, ring_centre, 2) # 5 cnt = 0 for iatom in oxy_ring_atoms: positions[iatom] = oxy_ring_positions[cnt] cnt += 1 print_intermediate = True if print_intermediate: molecule = atoms.Atoms(species, positions) write.xyz("select.xyz", molecule) quit('up to here - looks like things move unexpectedly') # Assume Br-O bond length bond_length_bo = 1.7 # For each Si-O-O of a former tetrahedron, move a unit towards each of the two closest ring oxygens # cleave off one of the oxy and convert Si -> Br translated_species = [] translated_positions = [] for si_oo_unit in si_oo_units: neighbouring_ring_atoms = find_closest_ring_oxygens( species, positions, si_oo_unit) ts, tp = translate_si_o_o_unit(species, positions, si_oo_unit, neighbouring_ring_atoms) translated_species += ts translated_positions += tp # Remove old atoms atom_indices = np.delete(np.arange(0, n_atoms), flatten(si_oo_units)) new_species = [] new_positions = [] for iatom in atom_indices: new_species.append(species[iatom]) new_positions.append(positions[iatom]) # Add new atoms assert len(translated_species) % 2 == 0 for iatom in range(0, len(translated_species)): new_species.append(translated_species[iatom]) new_positions.append(translated_positions[iatom]) assert (len(new_species) == len(new_positions)) # Smart way to do this is to create sets of pair indices from the translated silicons, # then put oxygens between them # I always do operations in pairs, so should go [b,o,b,o,b,o...] => elements 0 and 2 are a pair in the ring. n_atoms = len(new_species) boron_indices = [i for i in range(0, n_atoms) if new_species[i] == 'B'] # Create list of pairs boron_pairs = [] for i in range(0, len(boron_indices), 2): boron_A = boron_indices[i] boron_B = boron_indices[i + 1] print(new_species[boron_A], new_species[boron_B]) boron_pairs.append([boron_A, boron_B]) # Put oxygens between these pairs for pair in boron_pairs: pos_A = np.asarray(new_positions[pair[0]]) pos_B = np.asarray(new_positions[pair[1]]) print(np.linalg.norm(pos_A - pos_B)) pos_oxy = 0.5 * (pos_A + pos_B) new_positions.append(pos_oxy.tolist()) new_species.append('O') return new_species, new_positions
def dummy_fcc(): system_label = 'dummy_fcc' al = 10 unit_cell = atoms.Atoms(['Si'], [[0, 0, 0]]) lattice_vectors = bravais.face_centred_cubic(al) return System(system_label, unit_cell, lattice_vectors, al)