def generate_vacancy_structure(self, Nvac_sites=None, Nvac_clusters=None, cluster_size=None, vac_type='single', uniform=False, bin_axis='z', vac_bounds=None, Ntubes=None, vmd_selection_radius=np.sqrt(10.5), show_vmd_selection_cmd=True): """Generate vacancy structure. Parameters ---------- Nvac_sites : int, optional total number of vacancy sites to "add" to structure data. Nvac_clusters : int, optional total number of vacancy cluster sites to "add" to structure data. vac_type : {'single', 'double', 'triple'}, optional uniform : bool, optional Generate uniform vacancies in structure data. bin_axis : {'x', 'y', 'z'}, optional axis along which to generate uniform vacancies Ntubes : {None, int}, optional show_vmd_selection_cmd : bool, optional Generate a VMD selection string that can be used to select the atoms surrounding the vacancies. vmd_selection_radius : float, optional Cutoff radius for VMD selection command in units of **Angstroms**. Raises ------ TypeError If `Nvac_sites` is `None` and `Nvac_clusters` is `None` or if `uniform` is `True` and the `structure_data` was read in from a file and `Ntubes` is `None`. """ if Nvac_sites is None and Nvac_clusters is None: raise TypeError('`Nvac_sites` or `Nvac_clusters` must be an ' 'integer.') elif Nvac_sites is None and Nvac_clusters is not None: Nvac_sites = Nvac_clusters if cluster_size is None: cluster_size = 1 self._Nvac_sites = Nvac_sites self._Nvac_clusters = Nvac_clusters self._cluster_size = cluster_size self._vac_type = vac_type self._vmd_selection_radius = vmd_selection_radius self._show_vmd_selection_cmd = show_vmd_selection_cmd bin_axis_index = xyz.index(bin_axis) if uniform: if Ntubes is None: Ntubes = self._Ntubes if not isinstance(Ntubes, int): raise TypeError('`Ntubes` must be specified as an integer.') Natoms = len(self._atom_ids) if self._Natoms_per_tube is not None: Natoms_per_tube = self._Natoms_per_tube else: Natoms_per_tube = int(Natoms / Ntubes) Nvac_sites_per_tube = int(Nvac_sites / Ntubes) extra = Nvac_sites % Ntubes nbins = Ntubes * Nvac_sites_per_tube bin_sets = [] for n in range(Ntubes): bin_sets.append(np.arange(n, Nvac_sites, Ntubes)) bin_set_iter = itertools.cycle((bin_sets)) vac_bin_edges = np.linspace(self._atom_coords.T[bin_axis].min(), self._atom_coords.T[bin_axis].max(), num=nbins+1) vac_coords_along_bin_axis = \ vac_bin_edges[:-1] + np.diff(vac_bin_edges) / 2 if self._verbose: print('Ntubes: {}'.format(Ntubes)) print('Natoms: {}'.format(Natoms)) print('Natoms_per_tube: {}'.format(Natoms_per_tube)) print('Nvac_sites: {}'.format(Nvac_sites)) print('Nvac_sites_per_tube: {}'.format(Nvac_sites_per_tube)) print('extra vacancies: {}'.format(extra)) print('nbins: {}'.format(nbins)) print('bin_sets:\n{}'.format(bin_sets)) print('vac_bin_edges:' '\n{}'.format(vac_bin_edges)) print('vac_coords_along_bin_axis:' '\n{}'.format(vac_coords_along_bin_axis)) for i in range(Ntubes): tube_atom_indices = \ np.where((self._atom_ids > (Natoms_per_tube * i)) & (self._atom_ids <= (Natoms_per_tube * (i + 1)))) tube_atom_ids = self._atom_ids[tube_atom_indices] tube_coords = self._atoms.filter_ids(tube_atom_ids, invert=False).coords if self._verbose: print('tube n: {:d}'.format(i + 1)) print('tube_atom_ids:\n{}'.format(tube_atom_ids)) print('tube_atom_coords:\n{}'.format(tube_coords)) bin_set = next(bin_set_iter) for vac_pos in vac_coords_along_bin_axis[bin_set]: candidate_vac_atom_indices = \ np.where(np.abs(tube_coords.T[bin_axis_index] - vac_pos) <= 1) candidate_vac_atom_ids = \ tube_atom_ids[candidate_vac_atom_indices] if self._verbose: print('vac_pos along {}-axis: {:.2f} \u00c5'.format( bin_axis, vac_pos)) print('N candidate_vac_atom_ids: ' '{}\n'.format(len(candidate_vac_atom_ids))) self._vac_ids = \ np.r_[self._vac_ids, np.random.choice(candidate_vac_atom_ids)] else: super(NanotubeVacancyGenerator, self)._random_vacancy_generator() super(NanotubeVacancyGenerator, self)._generate_vacancy_structure()
def generate_vacancy_structure(self, Nvac_sites=None, Nvac_clusters=None, cluster_size=None, vac_type='single', uniform=False, bin_axis='z', vac_bounds=None, Ntubes=None, vmd_selection_radius=np.sqrt(10.5), show_vmd_selection_cmd=True): """Generate vacancy structure. Parameters ---------- Nvac_sites : int, optional total number of vacancy sites to "add" to structure data. Nvac_clusters : int, optional total number of vacancy cluster sites to "add" to structure data. vac_type : {'single', 'double', 'triple'}, optional uniform : bool, optional Generate uniform vacancies in structure data. bin_axis : {'x', 'y', 'z'}, optional axis along which to generate uniform vacancies Ntubes : {None, int}, optional show_vmd_selection_cmd : bool, optional Generate a VMD selection string that can be used to select the atoms surrounding the vacancies. vmd_selection_radius : float, optional Cutoff radius for VMD selection command in units of **Angstroms**. Raises ------ TypeError If `Nvac_sites` is `None` and `Nvac_clusters` is `None` or if `uniform` is `True` and the `structure_data` was read in from a file and `Ntubes` is `None`. """ if Nvac_sites is None and Nvac_clusters is None: raise TypeError('`Nvac_sites` or `Nvac_clusters` must be an ' 'integer.') elif Nvac_sites is None and Nvac_clusters is not None: Nvac_sites = Nvac_clusters if cluster_size is None: cluster_size = 1 self._Nvac_sites = Nvac_sites self._Nvac_clusters = Nvac_clusters self._cluster_size = cluster_size self._vac_type = vac_type self._vmd_selection_radius = vmd_selection_radius self._show_vmd_selection_cmd = show_vmd_selection_cmd bin_axis_index = xyz.index(bin_axis) if uniform: if Ntubes is None: Ntubes = self._Ntubes if not isinstance(Ntubes, int): raise TypeError('`Ntubes` must be specified as an integer.') Natoms = len(self._atom_ids) if self._Natoms_per_tube is not None: Natoms_per_tube = self._Natoms_per_tube else: Natoms_per_tube = int(Natoms / Ntubes) Nvac_sites_per_tube = int(Nvac_sites / Ntubes) extra = Nvac_sites % Ntubes nbins = Ntubes * Nvac_sites_per_tube bin_sets = [] for n in range(Ntubes): bin_sets.append(np.arange(n, Nvac_sites, Ntubes)) bin_set_iter = itertools.cycle((bin_sets)) vac_bin_edges = np.linspace(self._atom_coords.T[bin_axis].min(), self._atom_coords.T[bin_axis].max(), num=nbins + 1) vac_coords_along_bin_axis = \ vac_bin_edges[:-1] + np.diff(vac_bin_edges) / 2 if self._verbose: print('Ntubes: {}'.format(Ntubes)) print('Natoms: {}'.format(Natoms)) print('Natoms_per_tube: {}'.format(Natoms_per_tube)) print('Nvac_sites: {}'.format(Nvac_sites)) print('Nvac_sites_per_tube: {}'.format(Nvac_sites_per_tube)) print('extra vacancies: {}'.format(extra)) print('nbins: {}'.format(nbins)) print('bin_sets:\n{}'.format(bin_sets)) print('vac_bin_edges:' '\n{}'.format(vac_bin_edges)) print('vac_coords_along_bin_axis:' '\n{}'.format(vac_coords_along_bin_axis)) for i in range(Ntubes): tube_atom_indices = \ np.where((self._atom_ids > (Natoms_per_tube * i)) & (self._atom_ids <= (Natoms_per_tube * (i + 1)))) tube_atom_ids = self._atom_ids[tube_atom_indices] tube_coords = self._atoms.filter_ids(tube_atom_ids, invert=False).coords if self._verbose: print('tube n: {:d}'.format(i + 1)) print('tube_atom_ids:\n{}'.format(tube_atom_ids)) print('tube_atom_coords:\n{}'.format(tube_coords)) bin_set = next(bin_set_iter) for vac_pos in vac_coords_along_bin_axis[bin_set]: candidate_vac_atom_indices = \ np.where(np.abs(tube_coords.T[bin_axis_index] - vac_pos) <= 1) candidate_vac_atom_ids = \ tube_atom_ids[candidate_vac_atom_indices] if self._verbose: print('vac_pos along {}-axis: {:.2f} \u00c5'.format( bin_axis, vac_pos)) print('N candidate_vac_atom_ids: ' '{}\n'.format(len(candidate_vac_atom_ids))) self._vac_ids = \ np.r_[self._vac_ids, np.random.choice(candidate_vac_atom_ids)] else: super(NanotubeVacancyGenerator, self)._random_vacancy_generator() super(NanotubeVacancyGenerator, self)._generate_vacancy_structure()
def generate_vacancy_structure(self, Nvac_sites=None, Nvac_clusters=None, cluster_size=None, vac_type='single', uniform=False, bin_axis='z', distribute_evenly=False, vmd_selection_radius=np.sqrt(10.5), show_vmd_selection_cmd=True): """Generate vacancy structure. Parameters ---------- Nvac_sites : int, optional total number of vacancy sites to "add" to structure data. Nvac_clusters : int, optional total number of vacancy cluster sites to "add" to structure data. vac_type : {'single', 'double', 'triple'}, optional uniform : bool, optional Generate vacancies uniformly distributed along `bin_axis`. bin_axis : {'x', 'y', 'z'}, optional axis along which to generate uniform vacancies distribute_evenly : bool, optional show_vmd_selection_cmd : bool, optional Generate a VMD selection string that can be used to select the atoms surrounding the vacancies. vmd_selection_radius : float, optional Cutoff radius for VMD selection command in units of **Angstroms**. Raises ------ `TypeError` If `Nvac_sites` is `None` and `Nvac_clusters` is `None` """ if Nvac_sites is None and Nvac_clusters is None: raise TypeError('`Nvac_sites` or `Nvac_clusters` must ' 'be an integer.') elif Nvac_sites is None and Nvac_clusters is not None: Nvac_sites = Nvac_clusters if cluster_size is None: cluster_size = 1 self._Nvac_sites = Nvac_sites self._Nvac_clusters = Nvac_clusters self._cluster_size = cluster_size self._vac_type = vac_type self._vmd_selection_radius = vmd_selection_radius self._show_vmd_selection_cmd = show_vmd_selection_cmd bin_axis_index = xyz.index(bin_axis) if uniform: # find the coords of each layer y_coords = self._atom_coords['y'] Nlayers = len(set(y_coords)) layer_coords = np.asarray(sorted(list(set(y_coords)))) Nvac_sites_per_layer = int(Nvac_sites / Nlayers) extra = Nvac_sites % Nlayers nbins = Nvac_sites_per_layer * Nlayers bin_sets = [] for n in range(Nlayers): bin_sets.append(np.arange(n, nbins, Nlayers)) bin_set_iter = itertools.cycle((bin_sets)) bin_edges = np.linspace(self._atom_coords.T[bin_axis_index].min(), self._atom_coords.T[bin_axis_index].max(), num=nbins+1) bin_mid_pts = bin_edges[:-1] + np.diff(bin_edges) / 2 if self._verbose: print('Nlayers: {}'.format(Nlayers)) print('Nvac_sites: {}'.format(Nvac_sites)) print('Nvac_sites_per_layer: {}'.format(Nvac_sites_per_layer)) print('extra vacancies: {}'.format(extra)) print('nbins: {}'.format(nbins)) print('bin_sets:\n{}'.format(bin_sets)) print('bin_edges:\n{}'.format(bin_edges)) print('bin_mid_pts:\n{}'.format(bin_mid_pts)) ortho_axis = 'x' if bin_axis == 'z' else 'z' ortho_mid_pt = self._atom_coords[ortho_axis].min() + \ (self._atom_coords[ortho_axis].max() - self._atom_coords[ortho_axis].min()) / 2 atoms_along_ortho_axis = {'+': [], '-': []} for y in layer_coords: bin_set = next(bin_set_iter) for vac_pos in bin_mid_pts[bin_set]: candidate_vac_atom_indices = \ np.where( (self._atom_coords[ortho_axis] >= (self._atom_coords[ortho_axis].min() + 2.5)) & (self._atom_coords[ortho_axis] <= (self._atom_coords[ortho_axis].max() - 2.5)) & (np.abs(self._atom_coords['y'] - y) <= 0.5) & (np.abs(self._atom_coords.T[bin_axis_index] - vac_pos) <= 1)) candidate_vac_atom_ids = \ self._atom_ids[candidate_vac_atom_indices] if self._verbose: print('candidate_vac_atom_ids: ' '{}\n'.format(candidate_vac_atom_ids)) rand_vac_atom_id = None while True: rand_vac_atom_id = \ np.random.choice(candidate_vac_atom_ids) if distribute_evenly: rand_vac_atom = \ self._atoms.get_atoms(asarray=True)[ self._atom_ids == rand_vac_atom_id][0] ortho_pos = getattr(rand_vac_atom, ortho_axis) if ortho_pos >= ortho_mid_pt and \ len(atoms_along_ortho_axis['+']) < \ Nvac_sites_per_layer / 2: atoms_along_ortho_axis['+'].append( rand_vac_atom) break elif ortho_pos < ortho_mid_pt and \ len(atoms_along_ortho_axis['-']) < \ Nvac_sites_per_layer / 2: atoms_along_ortho_axis['-'].append( rand_vac_atom) break else: continue else: break self._vac_ids = np.r_[self._vac_ids, rand_vac_atom_id] else: super(GrapheneVacancyGenerator, self)._random_vacancy_generator() super(GrapheneVacancyGenerator, self)._generate_vacancy_structure()
def generate_vacancy_structure(self, Nvac_sites=None, Nvac_clusters=None, cluster_size=None, vac_type='single', uniform=False, bin_axis='z', distribute_evenly=False, vmd_selection_radius=np.sqrt(10.5), show_vmd_selection_cmd=True): """Generate vacancy structure. Parameters ---------- Nvac_sites : int, optional total number of vacancy sites to "add" to structure data. Nvac_clusters : int, optional total number of vacancy cluster sites to "add" to structure data. vac_type : {'single', 'double', 'triple'}, optional uniform : bool, optional Generate vacancies uniformly distributed along `bin_axis`. bin_axis : {'x', 'y', 'z'}, optional axis along which to generate uniform vacancies distribute_evenly : bool, optional show_vmd_selection_cmd : bool, optional Generate a VMD selection string that can be used to select the atoms surrounding the vacancies. vmd_selection_radius : float, optional Cutoff radius for VMD selection command in units of **Angstroms**. Raises ------ `TypeError` If `Nvac_sites` is `None` and `Nvac_clusters` is `None` """ if Nvac_sites is None and Nvac_clusters is None: raise TypeError('`Nvac_sites` or `Nvac_clusters` must ' 'be an integer.') elif Nvac_sites is None and Nvac_clusters is not None: Nvac_sites = Nvac_clusters if cluster_size is None: cluster_size = 1 self._Nvac_sites = Nvac_sites self._Nvac_clusters = Nvac_clusters self._cluster_size = cluster_size self._vac_type = vac_type self._vmd_selection_radius = vmd_selection_radius self._show_vmd_selection_cmd = show_vmd_selection_cmd bin_axis_index = xyz.index(bin_axis) if uniform: # find the coords of each layer y_coords = self._atom_coords['y'] Nlayers = len(set(y_coords)) layer_coords = np.asarray(sorted(list(set(y_coords)))) Nvac_sites_per_layer = int(Nvac_sites / Nlayers) extra = Nvac_sites % Nlayers nbins = Nvac_sites_per_layer * Nlayers bin_sets = [] for n in range(Nlayers): bin_sets.append(np.arange(n, nbins, Nlayers)) bin_set_iter = itertools.cycle((bin_sets)) bin_edges = np.linspace(self._atom_coords.T[bin_axis_index].min(), self._atom_coords.T[bin_axis_index].max(), num=nbins + 1) bin_mid_pts = bin_edges[:-1] + np.diff(bin_edges) / 2 if self._verbose: print('Nlayers: {}'.format(Nlayers)) print('Nvac_sites: {}'.format(Nvac_sites)) print('Nvac_sites_per_layer: {}'.format(Nvac_sites_per_layer)) print('extra vacancies: {}'.format(extra)) print('nbins: {}'.format(nbins)) print('bin_sets:\n{}'.format(bin_sets)) print('bin_edges:\n{}'.format(bin_edges)) print('bin_mid_pts:\n{}'.format(bin_mid_pts)) ortho_axis = 'x' if bin_axis == 'z' else 'z' ortho_mid_pt = self._atom_coords[ortho_axis].min() + \ (self._atom_coords[ortho_axis].max() - self._atom_coords[ortho_axis].min()) / 2 atoms_along_ortho_axis = {'+': [], '-': []} for y in layer_coords: bin_set = next(bin_set_iter) for vac_pos in bin_mid_pts[bin_set]: candidate_vac_atom_indices = \ np.where( (self._atom_coords[ortho_axis] >= (self._atom_coords[ortho_axis].min() + 2.5)) & (self._atom_coords[ortho_axis] <= (self._atom_coords[ortho_axis].max() - 2.5)) & (np.abs(self._atom_coords['y'] - y) <= 0.5) & (np.abs(self._atom_coords.T[bin_axis_index] - vac_pos) <= 1)) candidate_vac_atom_ids = \ self._atom_ids[candidate_vac_atom_indices] if self._verbose: print('candidate_vac_atom_ids: ' '{}\n'.format(candidate_vac_atom_ids)) rand_vac_atom_id = None while True: rand_vac_atom_id = \ np.random.choice(candidate_vac_atom_ids) if distribute_evenly: rand_vac_atom = \ self._atoms.get_atoms(asarray=True)[ self._atom_ids == rand_vac_atom_id][0] ortho_pos = getattr(rand_vac_atom, ortho_axis) if ortho_pos >= ortho_mid_pt and \ len(atoms_along_ortho_axis['+']) < \ Nvac_sites_per_layer / 2: atoms_along_ortho_axis['+'].append( rand_vac_atom) break elif ortho_pos < ortho_mid_pt and \ len(atoms_along_ortho_axis['-']) < \ Nvac_sites_per_layer / 2: atoms_along_ortho_axis['-'].append( rand_vac_atom) break else: continue else: break self._vac_ids = np.r_[self._vac_ids, rand_vac_atom_id] else: super(GrapheneVacancyGenerator, self)._random_vacancy_generator() super(GrapheneVacancyGenerator, self)._generate_vacancy_structure()