def slip_vector(system_0, system_1, neighbor_list=None, neighbor_list_cutoff=None): """Compute the slip vectors for all atoms in system_1 relative to system_0.""" assert system_0.natoms == system_1.natoms, 'systems have different number of atoms' #neighbor list setup if neighbor_list is not None: assert neighbor_list_cutoff is None, 'neighbor_list and neighbor_list_cutoff cannot both be given' elif neighbor_list_cutoff is not None: neighbor_list = am.nlist(system_0, neighbor_list_cutoff) elif 'neighbors' in system_0.prop: neighbor_list = system_0.prop['neighbors'] elif 'nlist' in system_0.prop: neighbor_list = system_0.prop['nlist'] if isinstance(neighbor_list, am.NeighborList): objectnlist = True else: objectnlist = False #Calculate the slip vector slip = np.zeros((system_0.natoms, 3)) for i in xrange(system_0.natoms): if objectnlist: js = neighbor_list[i] else: js = neighbor_list[i, 1:neighbor_list[i, 0] + 1] slip[i] = -np.sum(system_1.dvect(i, js) - system_0.dvect(i, js), axis=0) return slip
def slip_vector(system_0, system_1, neighbor_list=None, neighbor_list_cutoff=None): """Compute the slip vectors for all atoms in system_1 relative to system_0.""" assert system_0.natoms == system_1.natoms, 'systems have different number of atoms' #neighbor list setup if neighbor_list is not None: assert neighbor_list_cutoff is None, 'neighbor_list and neighbor_list_cutoff cannot both be given' elif neighbor_list_cutoff is not None: neighbor_list = am.nlist(system_0, neighbor_list_cutoff) elif 'neighbors' in system_0.prop: neighbor_list = system_0.prop['neighbors'] elif 'nlist' in system_0.prop: neighbor_list = system_0.prop['nlist'] if isinstance(neighbor_list, am.NeighborList): objectnlist = True else: objectnlist = False #Calculate the slip vector slip = np.zeros((system_0.natoms, 3)) for i in xrange(system_0.natoms): if objectnlist: js = neighbor_list[i] else: js = neighbor_list[i, 1:neighbor_list[i, 0]+1] slip[i] = -np.sum(system_1.dvect(i, js) - system_0.dvect(i, js), axis=0) return slip
def nlist(self, cutoff, cmult=1): """Build neighbor list for all atoms based on a cutoff. Keyword Arguments: cutoff -- radial cutoff distance for including atoms as neighbors. cmult -- int factor that changes the underlying binning algorithm. Default is 1, which should be the fastest. """ self.prop['nlist'] = am.nlist(self, cutoff, cmult)
def nlist(self, cutoff, cmult=1): """Build neighbor list for all atoms based on a cutoff. Keyword Arguments: cutoff -- radial cutoff distance for including atoms as neighbors. cmult -- int factor that changes the underlying binning algorithm. Default is 1, which should be the fastest. """ with warnings.catch_warnings(): warnings.simplefilter('always') warnings.warn('nlist method is replaced with neighbors method', DeprecationWarning) self.prop['nlist'] = am.nlist(self, cutoff, cmult=cmult)
def slip_vector(system_0, system_1, neighbor_list=None, neighbor_list_cutoff=None): """Compute the slip vectors for all atoms in system_1 relative to system_0.""" assert system_0.natoms == system_1.natoms, "systems have different number of atoms" # neighbor list setup if neighbor_list is not None: assert neighbor_list_cutoff is None, "neighbor_list and neighbor_list_cutoff cannot both be given" elif neighbor_list_cutoff is not None: neighbor_list = am.nlist(system_0, neighbor_list_cutoff) elif "nlist" in system_0.prop: neighbor_list = system_0.prop["nlist"] # Calculate the slip vector slip = np.zeros((system_0.natoms, 3)) for i in xrange(system_0.natoms): js = neighbor_list[i, 1 : neighbor_list[i, 0] + 1] slip[i] = -np.sum(system_1.dvect(i, js) - system_0.dvect(i, js), axis=0) return slip
def differential_displacement(base_system, disl_system, burgers_vector, plot_range, neighbor_list = None, neighbor_list_cutoff = None, component = 'standard', axes = None, plot_scale = 1, save_file = None, show = True): """ Function for generating a differential displacement plot for a dislocation containing system. Arguments: base_system -- atomman.System defect-free reference system corresponding to disl_system. disl_system -- atomman.System system containing the defect. burgers_vector -- 3x1 numpy array for the dislocation's Burgers vector. plot_range -- 3x3 numpy array specifying the Cartesian space to include atoms in the plot. Optional Keyword Arguments: neighbor_list -- pre-computed neighbor list for base_system. neighbor_list_cutoff -- cutoff for computing a neighbor list for base_system. component -- indicates the style of the calculation to use. axes -- 3x3 numpy array indicating the crystallographic axes corresponding to the box's Cartesian axes. If given, only used for transforming the burgers_vector. plot_scale -- scalar for multiplying the magnitude of the differential displacement arrows. save_file -- if given then the plot will be saved to a file with this name. show -- Boolean flag for showing the figure. Default is True. """ #Burgers vector setup if axes is not None: T = am.tools.axes_check(axes) burgers_vector = T.dot(burgers_vector) burgers_vector_magnitude = np.linalg.norm(burgers_vector) burgers_vector_uvect = burgers_vector / burgers_vector_magnitude #neighbor list setup if neighbor_list is not None: assert neighbor_list_cutoff is None, 'neighbor_list and neighbor_list_cutoff cannot both be given' elif neighbor_list_cutoff is not None: neighbor_list = am.nlist(base_system, neighbor_list_cutoff) elif 'nlist' in base_system.prop: neighbor_list = base_system.prop['nlist'] #Identify atoms in plot range base_pos = base_system.atoms_prop(key='pos') plot_range_indices = np.where((base_pos[:, 0] > plot_range[0,0]) & (base_pos[:, 0] < plot_range[0,1]) & (base_pos[:, 1] > plot_range[1,0]) & (base_pos[:, 1] < plot_range[1,1]) & (base_pos[:, 2] > plot_range[2,0]) & (base_pos[:, 2] < plot_range[2,1]))[0] #initial plot setup and parameters fig, ax1, = plt.subplots(1, 1, squeeze=True, figsize=(7,7), dpi=72) ax1.axis([plot_range[0,0], plot_range[0,1], plot_range[1,0], plot_range[1,1]]) atom_circle_radius = burgers_vector_magnitude / 10 arrow_width_scale = 1. / 200. #Loop over all atoms i in plot range for i in plot_range_indices: #Plot a circle for atom i color = cm.hsv((base_pos[i, 2] - plot_range[2,0]) / (plot_range[2,1] - plot_range[2,0])) ax1.add_patch(mpatches.Circle(base_pos[i, :2], atom_circle_radius, fc=color)) #make list of all neighbors for atom i neighbor_indices = neighbor_list[i, 1 : neighbor_list[i, 0] + 1] #Compute distance vectors between atom i and its neighbors for both systems base_dvectors = base_system.dvect(int(i), neighbor_indices) disl_dvectors = disl_system.dvect(int(i), neighbor_indices) #Compute differential displacement vectors dd_vectors = disl_dvectors - base_dvectors #Compute centerpoint positions for the vectors arrow_centers = base_pos[i] + base_dvectors / 2 if component == 'standard': #compute unit distance vectors base_uvectors = base_dvectors / np.linalg.norm(base_dvectors, axis=1)[:,np.newaxis] #compute component of the dd_vector parallel to the burgers vector dd_components = dd_vectors.dot(burgers_vector_uvect) dd_components[dd_components > burgers_vector_magnitude / 2] -= burgers_vector_magnitude dd_components[dd_components < -burgers_vector_magnitude / 2] += burgers_vector_magnitude #scale arrow lengths and vectors arrow_lengths = base_uvectors * dd_components[:,np.newaxis] * plot_scale arrow_widths = arrow_width_scale * dd_components * plot_scale #plot the arrows for center, length, width in zip(arrow_centers, arrow_lengths, arrow_widths): if width > 1e-7: ax1.quiver(center[0], center[1], length[0], length[1], pivot='middle', angles='xy', scale_units='xy', scale=1, width=width) elif component == 'xy': #scale arrow lengths and vectors arrow_lengths = dd_vectors[:, :2] * plot_scale arrow_lengths[dd_vectors[:, 2] > 0] *= -1 arrow_widths = arrow_width_scale * (arrow_lengths[:,0]**2+arrow_lengths[:,1]**2)**0.5 #plot the arrows for center, length, width in zip(arrow_centers, arrow_lengths, arrow_widths): if width > 1e-7: ax1.quiver(center[0], center[1], length[0], length[1], width=width, pivot='middle', angles='xy', scale_units='xy', scale=1) if save_file is not None: plt.savefig(save_file, dpi=800) if show == False: plt.close(fig) plt.show()
def nye_tensor(system, p_vectors, theta_max = 27, axes=None, neighbor_list=None, neighbor_list_cutoff=None): """Computes strain properties and Nye tensor for a defect containing system.""" #neighbor list setup if neighbor_list is not None: assert neighbor_list_cutoff is None, 'neighbor_list and neighbor_list_cutoff cannot both be given' elif neighbor_list_cutoff is not None: neighbor_list = am.nlist(system, neighbor_list_cutoff) elif 'nlist' in system.prop: neighbor_list = system.prop['nlist'] #If p_vectors is only given for one atom, apply to all atoms if len(p_vectors) == 1: p_vectors = np.broadcast_to(p_vectors, (system.natoms, len(p_vectors[0]), 3)) elif len(p_vectors) != system.natoms: p_vectors = np.broadcast_to(p_vectors, (system.natoms, len(p_vectors), 3)) #If axes are given, transform p accordingly if axes is not None: p_vectors = np.inner(p_vectors, am.tools.axes_check(axes)) #get cos of theta_max cos_theta_max = np.cos(theta_max * np.pi / 180) #Define identity and epsilon arrays #iden = eps = np.array([[[ 0, 0, 0],[ 0, 0, 1],[ 0,-1, 0]], [[ 0, 0,-1],[ 0, 0, 0],[ 1, 0, 0]], [[ 0, 1, 0],[-1, 0, 0],[ 0, 0, 0]]]) #Identify largest number of nearest neighbors nmax = 0 for ns in neighbor_list: if ns[0] > nmax: nmax=ns[0] #Initialize variables (done here to reduce memory allocations making it slightly faster) strain = np.empty((system.natoms, 3, 3)) inv1 = np.empty(system.natoms) inv2 = np.empty(system.natoms) ang_vel = np.empty(system.natoms) nye = np.empty((system.natoms, 3, 3)) P = np.zeros((nmax, 3)) Q = np.zeros((nmax, 3)) G = np.empty((system.natoms, 3, 3)) gradG = np.empty((3, 3, 3)) #Loop to calculate correspondence tensor, G, and strain data for i in xrange(system.natoms): p = np.asarray(p_vectors[i]) if p.ndim == 1: p = np.array([p]) p_mags = np.linalg.norm(p, axis=1) r1 = p_mags.min() #Calculate radial neighbor vectors, q q = system.dvect(i, neighbor_list[i][1:neighbor_list[i][0]+1]) if q.ndim == 1: q = np.array([q]) q_mags = np.linalg.norm(q, axis=1) #Calculate cos_thetas between all p's and q's. cos_thetas = (np.dot(p, q.T) /q_mags ).T / p_mags #Identify best index matches index_pairing = cos_thetas.argmax(1) #Exclude values where theta is greater than theta_max index_pairing[cos_thetas.max(1) < cos_theta_max] = -1 #Search for duplicate index_pairings u, u_count = np.unique(index_pairing, return_counts=True) for match in u[(u!=-1) & (u_count > 1)]: print index_pairing==match for n in xrange(neighbor_list[i][0]): #Check if the particular p has already been assigned to another q #Remove the p-q pair that is farther from r1 if index_pairing[n] >=0: for k in xrange(n): if index_pairing[n] == index_pairing[k]: nrad = abs(r1 - q_mags[n]) krad = abs(r1 - q_mags[k]) if nrad < krad: index_pairing[k]=-1 else: index_pairing[n]=-1 #Construct reduced P, Q matrices from p-q pairs c = 0 for n in xrange(neighbor_list[i][0]): if index_pairing[n] >= 0: Q[c] = q[n] P[c] = p[index_pairing[n]] c+=1 #Compute lattice correspondence tensor, G, from P and Q if c == 0: G[i] = np.identity(3) warnings.warn('An atom lacks pair sets. Check neighbor list') else: G[i], resid, rank, s = np.linalg.lstsq(Q[:c], P[:c]) #Compute strain properties strain[i] = ((np.identity(3) - G[i]) + (np.identity(3) - G[i]).T) / 2. inv1[i] = strain[i,0,0] + strain[i,1,1] + strain[i,2,2] inv2[i] = (strain[i,0,0] * strain[i,1,1] + strain[i,0,0] * strain[i,2,2] + strain[i,1,1] * strain[i,2,2] - strain[i,0,1]**2 - strain[i,0,2]**2 - strain[i,1,2]**2) rot = ((np.identity(3) - G[i]) - (np.identity(3) - G[i]).T) / 2. ang_vel[i] = (rot[0,1]**2 + rot[0,2]**2 + rot[1,2]**2)**0.5 #Construct the gradient tensor of G, gradG for i in xrange(system.natoms): neighbors = neighbor_list[i][1:neighbor_list[i][0]+1] Q = system.dvect(i, neighbors) if Q.ndim == 1: Q = np.array([Q]) dG = G[neighbors] - G[i] for x in xrange(3): gradG[x,:] = np.linalg.lstsq(Q, dG[:,x,:])[0].T #Use gradG to build the nye tensor, nye nye[i] = -np.einsum('ijm,ikm->jk', eps, gradG) return {'strain':strain, 'strain_invariant_1':inv1, 'strain_invariant_2':inv2, 'angular_velocity':ang_vel, 'Nye_tensor':nye}