def compute_density_all(data_file, dfile): ''' Calculate density at all steps in .d file ''' # data_file - LAMMPS .data file # dfile - LAMMPS .d file # # Returns a list of time steps and a list of corresponding densities # time steps are ints, densities are doubles # # Extract time steps time_steps = dsec.extract_all_sections(dfile, 'ITEM: TIMESTEP') # Extract box dimensions box_dims = dsec.extract_all_sections(dfile, 'ITEM: BOX') # Get total system mass in g total_mass = utils.compute_total_mass(data_file) # Compute densities and convert time steps to ints densities = [] int_steps = [] for step, box in zip(time_steps, box_dims): int_steps.append(int(step[0])) # Compute volume in cm^3 flt_box = utils.conv_to_float(box) vol = utils.compute_volume(flt_box) # Compute and store bulk density in g/cm^3 densities.append(total_mass/vol) return int_steps, densities
def plot_atom_ID(fname, atomID, colors, time): ''' Visualize an atom with given ID during the simulation ''' # fname - name of the d file # atomID - atom ID # colors - colors, list of RGB tuples, one per time step # time - array with simulation times # Extract time steps time_steps = dsec.extract_all_sections(fname, 'ITEM: TIMESTEP') # Extract atom data atoms_all_t = dsec.extract_all_sections(fname, 'ITEM: ATOMS') ist = 0 for step, atoms in zip(time_steps, atoms_all_t): if not (int(step[0]) in time): continue atom_data = [] for at in atoms: at = at.strip().split() if at[0] == str(atomID): atom_data.append([float(at[2]), float(at[3]), float(at[4])]) atom_np = np.array(atom_data, dtype=np.float32) mlab.points3d(atom_np[:, 0], atom_np[:, 1], atom_np[:, 2], color=colors[ist]) ist += 1 mlab.show()
def compute_average_conductivity(dfile, atom_type, atom_charge, efield, vel_col): ''' Computes electric conductivity averaged across all steps in the d file ''' # dfile - LAMMPS .d file # atom_type - atom type ID as defined in .data file # atom_charge - atom charge in C # efield - strength of the electric field in V/m # vel_col - column number for velocity component parallel # to the electric field direction # # Returns average conductivity in S/m, time steps in fs, and # a list of conductivities in S/m for each time step # Collect all data for this type of atom time, data = dsec.extract_atom_type_data(dfile, atom_type) # For each time compute average velocity over all atoms # convert to m/s Afs2ms = 1.0e5 vel_w_time = [] natom = len(data[0]) for step, frame in zip(time, data): ave_frame = 0.0 for line in frame: ave_frame += line[vel_col] vel_w_time.append(ave_frame / len(frame) * Afs2ms) # Average velocity across all time steps ave_vel_tot = sum(vel_w_time) / len(vel_w_time) # Average volume at each time step # Extract box dimensions, compute volumes at each step in m^3 cm32m3 = 1.0e-6 box_dims = dsec.extract_all_sections(dfile, 'ITEM: BOX') vols = [] for box in box_dims: flt_box = utils.conv_to_float(box) vols.append(utils.compute_volume(flt_box) * cm32m3) # Average electric conductivities over time steps # and within time steps cond_w_time = [ vel / vol * natom * atom_charge / efield for vel, vol in zip(vel_w_time, vols) ] ave_cond = sum(cond_w_time) / len(cond_w_time) return ave_cond, time, cond_w_time
def compute_coordination_number_all(dfile, atom_type_1, atom_type_2, dR=0.1, Rmax=10, steps=None): ''' Compute coordination number as a function of distance between two types of atoms at all time steps ''' # # dfile - LAMMPS .d file # atom_type_1, atom_type_2 - integer atom type IDs as specified in the Masses part of .data file # atom_type_1 is the type which coordination numbers will be returned (the central atom) # dR - width of a single shell for counting atoms at a given distance # Rmax - max radius around the central atom to consider # steps - optional list of timesteps to consider, all if not specified # # Returns a list of time steps and a list of lists of corresponding coordination numbers # with first list being radial distance, and second list the coordination number for # that distance; the radial distance is the center of each shell considered a # single position. # # Time steps and coordination numbers are ints, radial distances are doubles # # Extract time steps time_steps = dsec.extract_all_sections(dfile, 'ITEM: TIMESTEP') # Extract atom data atom_data = dsec.extract_all_sections(dfile, 'ITEM: ATOMS') # Compute coordination numbers as function of position # and convert time steps to ints cn_all = [] int_steps = [] for step, atom in zip(time_steps, atom_data): step_int = int(step[0]) # If selected steps, then skip ones not needed if steps: if not (step_int in steps): continue int_steps.append(step_int) # Retrieve all data for these atom types at_data_1 = utils.get_atom_i_data(atom, atom_type_1, 1, [2, 3, 4]) if atom_type_1 == atom_type_2: at_data_2 = at_data_1 else: at_data_2 = utils.get_atom_i_data(atom, atom_type_2, 1, [2, 3, 4]) # Compute and store distances between each atom in 1 and each atom in 2 # One sublist per atom from atom type 1 dist_12 = [] for at1 in at_data_1: temp_dist = [] for at2 in at_data_2: temp_dist.append(utils.compute_distance(at1, at2)) dist_12.append(temp_dist) # Compute coordination numbers ri, ci = compute_cn(dist_12, dR, Rmax) cn_all.append([ri, ci]) return int_steps, cn_all
def compute_spatial_stress(fname, time, nbins, idir, wpos=[], all_steps=False, av_per_atom=False): ''' Compute spatial distribution of stress ''' # # fname - name of the d file # time - array with simulation times to plot # nbins - number of bins in the target direction # idir - string representing direction # wpos - positions of walls in a non-periodic system # all_steps - include all time steps # av_per_atom - return average stress per atom rather than total # # Extract time steps time_steps = dsec.extract_all_sections(fname, 'ITEM: TIMESTEP') # Extract atom data atoms_all_t = dsec.extract_all_sections(fname, 'ITEM: ATOMS') # Extract box dimensions box_all_t = dsec.extract_all_sections(fname, 'ITEM: BOX') # Direction settings # b_ind - index of coordinates in the BOX data # d_ind - column with atom positions in that direction in the .d file if idir == 'x': b_ind = 0 d_ind = 2 elif idir == 'y': b_ind = 1 d_ind = 3 elif idir == 'z': b_ind = 2 d_ind = 4 else: raise RuntimeError('Wrong direction: ' + idir) # Stress components directions = ['xx', 'yy', 'zz', 'xy', 'xz', 'yz'] # ..and their position in d file (starts from 0) columns = [8, 9, 10, 11, 12, 13] stress = [] for step, atoms, box in zip(time_steps, atoms_all_t, box_all_t): if (not (int(step[0]) in time)) and (all_steps == False): continue # Spatial bins dims = box[b_ind].strip().split() if wpos: L_0 = wpos[0] L_tot = wpos[1] - wpos[0] else: L_0 = float(dims[0]) L_tot = float(dims[1]) - L_0 bin_width = L_tot / nbins atoms_in_bins = [0] * nbins # Compute volume in A^3 flt_box = utils.conv_to_float(box) # Compute volume in cm^3 then convert to A^3 cm32A3 = 1.0e24 vol = utils.compute_volume(flt_box) * cm32A3 bin_vol = vol / nbins # All stress components temp_stress = {} for key in directions: temp_stress[key] = [0] * nbins # Sum stresses in each bin and each direction for at in atoms: at = at.strip().split() # So that the binning is simple # Shifted the interval to 0->L_tot norm_pos = float(at[d_ind]) - L_0 ind = max(min(math.floor(norm_pos / bin_width), nbins - 1), 0) atoms_in_bins[ind] += 1 for key, col in zip(directions, columns): temp_stress[key][ind] += float(at[col]) if av_per_atom: # Divide by number of atoms in each bin for key, value in temp_stress.items(): temp_stress[key] = [ x / max(y, 1) for x, y in zip(value, atoms_in_bins) ] else: for key, value in temp_stress.items(): temp_stress[key] = [x / bin_vol for x in value] stress.append(temp_stress) return stress
def compute_spatial_density(fname, typeID, time, nbins, idir, wpos=[], all_steps=False, den=False): ''' Compute spatial density distribution of given atom type ''' # # fname - name of the d file # typeID - atom type as defined in .data file # time - array with simulation times to plot # nbins - number of bins in the target direction # idir - string representing direction # wpos - positions of walls in a non-periodic system # # Extract time steps time_steps = dsec.extract_all_sections(fname, 'ITEM: TIMESTEP') # Extract atom data atoms_all_t = dsec.extract_all_sections(fname, 'ITEM: ATOMS') # Extract box dimensions box_all_t = dsec.extract_all_sections(fname, 'ITEM: BOX') # Direction settings # b_ind - index of coordinates in the BOX data # d_ind - column with atom positions in that direction in the .d file if idir == 'x': b_ind = 0 d_ind = 2 elif idir == 'y': b_ind = 1 d_ind = 3 else: b_ind = 2 d_ind = 4 densities = [] for step, atoms, box in zip(time_steps, atoms_all_t, box_all_t): if (not (int(step[0]) in time)) and (all_steps == False): continue # Spatial bins dims = box[b_ind].strip().split() if wpos: L_0 = wpos[0] L_tot = wpos[1] - wpos[0] else: L_0 = float(dims[0]) L_tot = float(dims[1]) - L_0 bin_width = L_tot / nbins number_density = [0] * nbins # Calculate how many atoms in each bin atom_data = [] for at in atoms: at = at.strip().split() if at[1] == str(typeID): # So that the binning is simple # Shifted the interval to 0->L_tot norm_pos = float(at[d_ind]) - L_0 number_density[max( min(math.floor(norm_pos / bin_width), nbins - 1), 0)] += 1 # Compute volume in cm^3 then convert to A^3 cm32A3 = 1.0e24 flt_box = utils.conv_to_float(box) vol = utils.compute_volume(flt_box) * cm32A3 bin_vol = vol / nbins if den: # Divide by bin volumes (all volumes equal) densities.append([x / bin_vol for x in number_density]) else: densities.append([x for x in number_density]) return densities