def build_column(self, pore, z, theta, correlation=True, var=0, correlation_length=0, pd=0, random_shift=True): """ Place a column at angle theta on xy plane with respect to a pore center :param pore: pore number (0 : npores - 1) :param z: mean z-positions of monomers in column :param theta: angle, with respect to pore center where column should be placed (degrees) :param correlation: adjust z positions so there is a correlation length :param var: variance in multivariate normal distribution used to make correlated points :param correlation_length: length for which correlation between stacked monomers to persist :param pd: Angle of wedge created between vertically adjacent monomers. Defined by angle between vectors extending from pore center to monomer head groups. :param random_shift: if True, randomly shift columns in z-direction by choosing a displacement from a uniform \ distribution bounded by (0, d), where d is the vertical distance between stacked monomers :param seed: random seed if you want to reproduce randomly displaced structures :type pore: int :type z: np.array :type theta: float :type correlation: bool :type var: float :type correlation_length: float :type pd: float :type random_shift: bool """ if correlation: z = z_correlation(z, correlation_length, v=var) if random_shift: dbwl = z[1] - z[0] # distance between stacked monomers z += np.random.uniform(0, dbwl) elif random_shift: dbwl = z[1] - z[0] # distance between stacked monomers z += np.random.uniform(0, dbwl) displaced_theta = pd natoms = self.LC_positions.shape[0] # number of atoms including ions pos = np.copy(self.LC_positions) pos[:, 0] += self.pore_radius displaced_pos = np.copy(pos) pos = transform.rotate_coords_z(pos, theta) displaced_pos = transform.rotate_coords_z(displaced_pos, theta + displaced_theta) column = np.zeros([z.size * natoms, 3]) before = np.array([0, 0, 0]) for l in range(z.size): if l % 2 == 0: column[l * natoms:(l + 1) * natoms, :] = transform.translate(pos, before, np.array([0, 0, z[l]])) else: column[l * natoms:(l + 1) * natoms, :] = transform.translate(displaced_pos, before, np.array([0, 0, z[l]])) self.names += self.LC_names self.all_residues += self.LC_residues column = transform.translate(column, before, [self.pore_centers[pore, 0], self.pore_centers[pore, 1], 0]) self.xyz = np.concatenate((self.xyz, column))
def theta_deviation(self, pd=False): ideal_column = np.zeros([self.nlayers, 3]) starting_position = np.array([self.pore_radius, 0, 0]) ideal_column[:, :] = starting_position if pd: ideal_column[1::2, :] = transform.rotate_coords_z(starting_position[np.newaxis, :], 33.9155266) #self.angle / 2) ideal_pore = np.zeros([ideal_column.shape[0] * self.ncol, 3]) ideal_pore[:self.nlayers, :] = ideal_column for i in range(1, self.ncol): ideal_pore[i * self.nlayers: (i + 1) * self.nlayers, :] = transform.rotate_coords_z( ideal_column, i * self.angle) # layer based systems # ideal_layer = np.zeros([5, 3]) # ideal_layer[0, :] = [self.pore_radius, 0, 0] # for i in range(1, 5): # ideal_layer[i, :] = transform.rotate_coords_z(ideal_layer[np.newaxis, 0, :], i * self.angle) # # ideal_pore = np.zeros([ideal_layer.shape[0] * self.nlayers, 3]) # for i in range(self.nlayers): # if pd and i % 2 == 1: # ideal_pore[i * ideal_layer.shape[0]: (i + 1) * ideal_layer.shape[0], :] = transform.rotate_coords_z( # ideal_layer, self.angle / 2) # else: # ideal_pore[i * ideal_layer.shape[0]: (i + 1) * ideal_layer.shape[0], :] = ideal_layer print('Calculating angles needed to minimize angular deviation') #angles = np.zeros([self.t.n_frames, self.npores]) angles = np.linspace(0, 360, self.nrotations) angular_deviations = np.zeros([self.t.n_frames, self.npores, self.ncol * self.nlayers]) for f in tqdm.tqdm(range(self.t.n_frames)): for p in range(self.npores): deviations = np.zeros([self.nrotations]) pos = self.com[f, p * self.ncol * self.nlayers:(p + 1) * self.ncol * self.nlayers, :2] center = self.p_centers[:, p, f] for i, x in enumerate(angles): deviations[i] = minimize_deviation(ideal_pore, x, pos, center) # , com, ideal_pore, p_centers) ideal = transform.rotate_coords_z(ideal_pore, angles[np.argmin(deviations)]) angular_deviations[f, p, :] = angular_deviation(pos, center, ideal) self.theta_values = angular_deviations self.theta_values[np.where(self.theta_values < 3)] += 2 * np.pi self.theta_values[np.where(self.theta_values > 3)] -= 2 * np.pi self.theta_values -= self.theta_values.mean() self.dtheta = np.std(self.theta_values)
def align_with_x(self): """ Align vector defined by lineatoms in LC object with x axis """ v = np.array([ self.LC_positions[self.lineatoms[0], :2] - self.LC_positions[self.lineatoms[1], :2] ]) angle = np.arctan(v[0, 1] / v[0, 0]) self.LC_positions = transform.rotate_coords_z(self.LC_positions, -angle * 180 / np.pi)
def build_column(self, pore, z, theta, correlation=True, var=0, correlation_length=0, pd=0, random_shift=True): """ Place a column at angle theta on xy plane with respect to a pore center :param pore: pore number (0 : npores - 1) :param z: mean z-positions of monomers in column :param theta: angle, with respect to pore center where column should be placed :param correlation: adjust z positions so there is a correlation length :param var: variance in multivariate normal distribution used to make correlated points :param correlation_length: length for which correlation between stacked monomers to persist :param pd: Specify a nonzero value to make a parallel displaced configuration. The distance here (in nm) will\ be the distance between the center of masses of two vertically stacked monomers. :param random_shift: if True, randomly shift columns in z-direction by choosing a displacement from a uniform \ distribution bounded by (0, d), where d is the vertical distance between stacked monomers :type pore: int :type z: np.array :type theta: float :type correlation: bool :type var: float :type correlation_length: float :type pd: float :type random_shift: bool """ if correlation: z = z_correlation(z, correlation_length, v=var) if random_shift: dbwl = z[1] - z[0] # distance between stacked monomers z += np.random.uniform(0, dbwl) elif random_shift: dbwl = z[1] - z[0] # distance between stacked monomers z += np.random.uniform(0, dbwl) displaced_theta = (180 / np.pi) * (2 * np.arcsin(pd / (2 * self.pore_radius))) natoms = self.LC_positions.shape[0] # number of atoms including ions pos = np.copy(self.LC_positions) pos[:, 0] += self.pore_radius displaced_pos = np.copy(pos) pos = transform.rotate_coords_z(pos, theta) displaced_pos = transform.rotate_coords_z(displaced_pos, theta + displaced_theta) column = np.zeros([z.size * natoms, 3]) before = np.array([0, 0, 0]) for l in range(z.size): if l % 2 == 0: column[l * natoms:(l + 1) * natoms, :] = transform.translate( pos, before, np.array([0, 0, z[l]])) else: column[l * natoms:(l + 1) * natoms, :] = transform.translate( displaced_pos, before, np.array([0, 0, z[l]])) self.names += self.LC_names self.all_residues += self.LC_residues column = transform.translate( column, before, [self.pore_centers[pore, 0], self.pore_centers[pore, 1], 0]) self.xyz = np.concatenate((self.xyz, column))
def minimize_deviation(ideal_pore, angle, com, p_center): ideal = transform.rotate_coords_z(ideal_pore, angle) # rotate pore uniformly by some angle return np.linalg.norm(angular_deviation(com, p_center, ideal)) # find deviation between ideal and actual positions