def atoms(self, constrained=True, parameters=DEFAULT): if parameters is DEFAULT: parameters = self.parameters() parameters = self.defaultParameters(parameters) vectors = np.array(parameters['vectors']) lengths = vectorLength(vectors, 1) assert lengths.all() atoms = self.__atoms.copy() pos = atoms.get_positions() size = np.array([pos[:, i].max() - pos[:,i].min() for i in range(3)]) size = size + parameters['length_scales']['correlation_length'] repeats = (1, 1, vectors[0][0]) vectors = atoms.cell[2] * vectors[0][0] atoms = atoms.repeat(repeats) atoms.set_cell(size) atoms.cell[2] = vectors atoms = removeCopies(atoms) atoms = orderAtoms(atoms) atoms = self.makeAtomsRelaxed(atoms, self.relaxation()) return atoms
def atoms(self, constrained=True, parameters=DEFAULT, ): system = self.fullyUnrelaxed() if parameters is DEFAULT: parameters = self.parameters() parameters = system.defaultParameters(parameters) slab = system.slab() slab_parameters = parameters['slab_parameters'] atoms = slab.atoms( constrained=constrained, initialized=True, parameters=slab_parameters, ) atoms = system.change(atoms, to='orth_system', fro='orth_defect') atoms.wrap(center=0) atoms = orderAtoms(atoms) molecule_atoms = self.moleculeAtoms(parameters=parameters['molecule_parameters']) atoms += molecule_atoms if len(molecule_atoms) > 0: name = self.name().replace(os.sep, '_') atoms.setRegion(name=name, picker=slice(-len(molecule_atoms), None), cell=atoms.get_cell(), pbc=[False, False, False]) atoms = self.makeAtomsRelaxed(atoms, self.relaxation()) return atoms
def crystalAtoms(self, start_layer=0, end_layer=1, coordinates='orth_surface', sub_layers=False, minimal=True, ): atoms = self.crystal().atoms() if sub_layers: in_equal_layers = self.inequivalentLayers() repeats = int(np.ceil(end_layer/float(in_equal_layers))) atoms = atoms.repeat((1, 1, repeats + 1)) atoms.positions -= self.crystal().unitCell()*(repeats) start_layer += in_equal_layers -1 end_layer += in_equal_layers -1 atoms = orderAtoms(atoms, (2, 1, 0)) sl = slice(start_layer, end_layer) groups = groupAtoms(atoms)[::-1][sl] if len(groups) == 0: atoms = Atoms([], cell=atoms.get_cell(), pbc=atoms.get_pbc()) else: atoms, indices = groups[0] for group, indices in groups[1:]: atoms += group else: cell = atoms.unitCell() atoms = atoms.repeat((1, 1, end_layer-start_layer)) atoms.positions += cell*start_layer return atoms
def makeSlab(surface, pertubation_length, correlation_length): vectors = surface.cell(coordinates='orth_crystal') atoms = makeSample(surface.crystal(), vectors) surface.change(atoms, to='orth_surface', fro='orth_crystal') vectors = surface.cell(coordinates='orth_surface') vectors, repeats = makeLargeEnoughQuiteOrthogonalBox(vectors, pertubation_length) atoms = atoms.repeat(repeats) # Make repetitions to satisfy correlation length. n2 = int(numpy.ceil(correlation_length/vectors[2,2])) atoms = atoms.repeat((1,1,n2)) # Wrap into box with atoms below zero in third direction. wrap_vectors = numpy.array([vectors[0], vectors[1], -n2*vectors[2]]) atoms.set_cell(wrap_vectors) atoms = wrap(atoms) atoms.set_cell(vectors) atoms.set_pbc([True, True, False]) # Crop number of layers. take = atoms.get_positions()[:, 2] > - correlation_length + 1e-5 atoms = atoms[take] extra_atoms = surface.extraAtoms('orth_surface') repeats = fitBoxIntoBox(extra_atoms.get_cell()[:2], vectors[:2]) repeats = list(repeats) repeats.append(1) extra_atoms = extra_atoms.repeat(tuple(repeats)) extra_atoms.set_cell(vectors) extra_atoms = wrap(extra_atoms) extra_atoms = removeCopies(extra_atoms) atoms += extra_atoms # Passivate lower surface. positions = atoms.get_positions() z_min = min(positions[:,2]) lower_positions = positions[(positions[:,2] < z_min + 1e-5)] h_positions = [position + [0,0,-0.8] for position in lower_positions] passivation = Atoms('H%d'%len(h_positions), h_positions) atoms += passivation # Make vaccum in the out-of-surface direction. z_pos = atoms.get_positions()[:, 2] z_min, z_max = min(z_pos), max(z_pos) z_diff = z_max - z_min tot_diff = correlation_length + z_diff atoms.cell[2] = numpy.array([0,0,tot_diff]) atoms = wrap(atoms) # Put atoms in order. atoms = orderAtoms(atoms) # Fix lowest coordinates. constraint = FixAtoms(mask=(atoms.get_positions()[:, 2] < -pertubation_length + 1e-5)) atoms.set_constraint(constraint) return atoms
def crystalAtoms(self, start_layer=0, end_layer=1, coordinates='orth_surface', vectors=((1,0),(0,1)), sub_layers=False, minimal=True, ): sl = slice(start_layer, end_layer) if minimal: unit_cell = self.minimalCell('crystal') else: unit_cell = self.cell('crystal') catoms = self.crystal().atoms() catoms.purgeTags() atoms = makeSlabWithVectors(catoms, unit_cell, sl.stop) atoms = self.change(atoms, to=coordinates, fro='orth_crystal') unit_cell = self.crystal().change(unit_cell, to='orth_crystal', fro='crystal', difference=True,)[:2] unit_cell = self.change(unit_cell, to='orth_surface', fro='orth_crystal') if len(atoms)==0: return atoms if minimal: vectors = unit_cell else: vectors = np.array(vectors) vectors = np.dot(unit_cell.transpose(), vectors.transpose()).transpose() repeats = fitBoxIntoBox(unit_cell, vectors) atoms = atoms.repeat(list(repeats) + [1]) out_vector = atoms.cell[2] out_vector[:2] = 0 vectors = np.array([vectors[0], vectors[1], out_vector]) atoms.set_cell(vectors) atoms.set_pbc([True, True, False]) atoms = removeCopies(atoms) atoms.wrap() atoms = orderAtoms(atoms, (2, 1, 0)) if sub_layers: groups = groupAtoms(atoms)[sl] if len(groups) == 0: return Atoms([], cell=atoms.get_cell(), pbc=atoms.get_pbc()) atoms, indices = groups[0] for atoms_group, indices in groups[1:]: atoms += atoms_group return atoms
def makeSlabWithVector(surface, vector, radius): v1 = numpy.zeros(3, dtype=numpy.int) v1[:2] = vector v1 = surface.change(v1, to='orth_surface', fro='surface') unit_cell = surface.unitCell('orth_surface') pro = [abs(numpy.dot(v, v1))/vectorLength(v) for v in unit_cell] v2 = unit_cell[numpy.argmin(pro)] l1 = vectorLength(v1) pro = vectorLength(numpy.cross(v1/l1, v2)) n2 = int(numpy.ceil(radius/pro)) v2 *= n2 v3 = surface.outOfPlaneVector('orth_surface') vectors = numpy.array([v1, v2, v3]) vectors = surface.change(vectors, to='crystal', fro='orth_surface') layer_distance = surface.outOfPlaneVector('orth_surface')[2] n_layers = int(numpy.ceil(radius/layer_distance)) atoms = makeSlabWithVectors(surface.crystal(), vectors, n_layers) surface.change(atoms, to='orth_surface', fro='orth_crystal') atoms.cell[2, :2] = 0 atoms.set_pbc([True, True, False]) atoms = wrap(atoms) # Make vaccum in the out-of-surface direction. z_pos = atoms.get_positions()[:, 2] z_min, z_max = min(z_pos), max(z_pos) z_diff = z_max - z_min tot_diff = radius + z_diff atoms.cell[2] = numpy.array([0,0,tot_diff]) atoms = wrap(atoms) # Put atoms in order. atoms = orderAtoms(atoms) return atoms
def atoms( self, parameters=DEFAULT, passivated=True, passivation_constrained=False, constrained=True, ): unrelaxed = self.fullyUnrelaxed() if parameters is DEFAULT: parameters = self.parameters() else: parameters = unrelaxed.defaultParameters(parameters) # Add outer surface layer. extra_atoms = unrelaxed.surfaceLayer(parameters) atoms = unrelaxed.crystalAtoms( start_layer=0, end_layer=parameters.nLayers(), sub_layers=True, ) atoms += extra_atoms pos = atoms.positions size = np.array([pos[:, i].max() - pos[:,i].min() for i in range(3)]) atoms.cell[:2,:2] = extra_atoms.cell[:2, :2] atoms = orderAtoms(atoms) if passivated: before = len(atoms) atoms = unrelaxed.passivateLowerSurface(atoms) after = len(atoms) n_passivated = after - before if constrained: fro, to = parameters['free_layers'], parameters.nLayers() constrain_mask = unrelaxed.findLayers(atoms, start_layer=fro, end_layer=to) else: constrain_mask = np.zeros(len(atoms), bool) if parameters['electrode_layers'] > 0: fro, to = parameters.nLayers() - parameters['electrode_layers'], parameters.nLayers() electrode_mask = unrelaxed.findLayers(atoms, start_layer=fro, end_layer=to) electrode_cell = unrelaxed.electrodeCell(parameters['electrode_layers'], atoms.get_cell()[:2]) central_mask = np.logical_not(electrode_mask) else: electrode_mask = np.zeros(len(atoms), int) electrode_cell = np.identity(3) central_mask = np.ones(len(atoms), int) if passivated and passivation_constrained: constrain_mask[:n_passivated] = True # Make vaccum in the out-of-surface direction. atoms.set_cell(np.array(parameters['cell_size']) + size) if electrode_mask.sum() > 0: electrode_cell[:2] = atoms.cell[:2] atoms.setRegion( name=self.crystal().name(), picker=electrode_mask, cell=electrode_cell, pbc=(False, False, (False, True)), ) atoms.setRegion(name=self.name(), picker=central_mask, cell=atoms.get_cell(), pbc=(False, False, False), ) if constrained: constraint = FixAtoms(mask=constrain_mask) atoms.set_constraint(constraint) cell_center = atoms.cell.sum(axis=0)/2 atoms_center = (atoms.positions.max(axis=0) + atoms.positions.min(axis=0))/2 move = cell_center - atoms_center atoms.set_celldisp(-move) atoms = self.makeAtomsRelaxed(atoms, self.relaxation()) return atoms
def atoms( self, constrained=True, initialized=True, parameters=DEFAULT, passivation_constrained=False, ): if parameters is DEFAULT: parameters = self.parameters() system = self.fullyUnrelaxed() basis_changer = system.basisChanger() parameters = system.defaultParameters(parameters) scales = parameters['length_scales'] electrode_sep = parameters.nLayers() - parameters['electrode_layers'] c_atoms = system.crystalAtoms( start_layer=electrode_sep, end_layer=parameters.nLayers(), vectors=parameters['vectors'], minimal=True, sub_layers=True, ) c_atoms += system.crystalAtoms( start_layer=0, end_layer=electrode_sep, vectors=parameters['vectors'], minimal=False, sub_layers=True, ) atoms = c_atoms.copy() vectors = system.fullCell(parameters) v3 = np.zeros(3) v3[2] = -abs(atoms.cell[2][2]) tmp_vectors = np.array([vectors[0], vectors[1], v3]) atoms.set_cell(tmp_vectors) atoms.set_pbc([True, True, False]) atoms.wrap() # Add outer surface layer. extra_atoms = system.surfaceLayer(parameters) atoms += extra_atoms atoms.cell[:2,:2] = extra_atoms.cell[:2, :2] if parameters['passivated']: before = len(atoms) atoms = self.passivateLowerSurface(atoms) after = len(atoms) n_passivated = after - before # Make vaccum in the out-of-surface direction. atoms.cell[2] = np.array([0,0, parameters['cell_size']]) if constrained: fro, to = parameters['free_layers'], parameters.nLayers() constrain_mask = system.findLayers(atoms, start_layer=fro, end_layer=to) else: constrain_mask = np.zeros(len(atoms), bool) if parameters['passivated'] and passivation_constrained: constrain_mask[:n_passivated] = True if initialized: atoms = system.initializedState(atoms) if parameters['electrode_layers'] > 0: fro, to = parameters.nLayers() - parameters['electrode_layers'], parameters.nLayers() mask = system.findLayers(atoms, start_layer=fro, end_layer=to) cell = system.electrodeCell(parameters['electrode_layers'], parameters['vectors']) atoms.setToRegion( name=self.crystal().name(), picker=mask, cell=cell, pbc=(True, True, (True, False)), ) mask = np.logical_not(mask) if mask.sum() >0: atoms.setToRegion(name=self.name(), picker=mask, cell=atoms.get_cell(), pbc=(True, True, False), ) constraint = FixAtoms(mask=constrain_mask) atoms.set_constraint(constraint) atoms.wrap(center=0, eps=0.01) atoms = orderAtoms(atoms) mask = system.findLayers(atoms, start_layer=0, end_layer=parameters.nLayers()) atoms.setTag('ReferenceBulk', picker=mask) atoms.setTag('Reference', picker=slice(-n_passivated, None)) atoms = self.makeAtomsRelaxed(atoms, self.relaxation()) return atoms