Exemple #1
0
    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))
Exemple #2
0
    def place_solute(self,
                     solute,
                     placement_point,
                     random=False,
                     freeze=False,
                     rem=.5):
        """
        Place solute at desired point and energy minimze the system
        :param solute: name of solute object (str)
        :param placement_point: point to place solute (np.array([3])
        :param random: place solute at random point in box (bool)
        :param freeze: freeze all atoms outside rem during energy minimization (bool)
        :param rem: radius from placement_point within which atoms will NOT be frozen (float, nm)
        :return:
        """

        # p = placement_point - (solute.com - solute.xyz[0, 0, :])  # want to move com to placement point
        #solute_positions = random_orientation(solute.xyz[0, ...], solute.xyz[0, 0, :] - solute.xyz[0, 1, :], placement_point)  # to be fixed in THE FUTURE
        solute_positions = transform.translate(
            solute.xyz[0, :, :], solute.com,
            placement_point)  # translate solute to placement point
        self.positions = np.concatenate(
            (self.positions, solute_positions))  # add to array of positions
        self.residues += solute.residues  # add solute residues to list of all residues
        self.names += solute.names  # add solute atom names to list of all names
        self.top.add_residue(solute, write=True)  # add 1 solute to topology

        # write new .gro file
        file_rw.write_gro_pos(self.positions,
                              self.intermediate_fname,
                              box=self.box_gromacs,
                              ids=self.names,
                              res=self.residues)

        if freeze:
            self.freeze_ndx(solute_placement_point=placement_point,
                            res=solute.resname)

        nrg = self.energy_minimize(self.em_steps, freeze=freeze)

        if nrg >= 0:
            self.revert(solute)
            if random:
                self.place_solute_random(solute)
            else:
                #self.remove_water(placement_point, 3)
                self.place_solute(solute, placement_point, freeze=False)
Exemple #3
0
    def translate_to_origin(self):
        """ Translate molecule to the origin using the ref_atom_index attribute of LC """

        self.LC_positions = transform.translate(
            self.LC_positions, self.LC_positions[self.ref_atom_index, :],
            [0, 0, 0])
Exemple #4
0
    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))
Exemple #5
0
def placement(z, pts, box):
    """
    :param z: z location where solute should be placed
    :param pts: points which run through the pore
    :return: location to place solute
    """

    # check if point is already in the spline
    if z in pts[:, 2]:

        ndx = np.where(pts[:, 2] == z)[0][0]

        return pts[ndx, :]
    # otherwise interpolate between closest spline points
    else:
        v = np.zeros([4, 2])  # vertices of unitcell box
        v[0, :] = [0, 0]
        v[1, :] = [box[0, 0], 0]
        v[3, :] = [box[1, 0], box[1, 1]]
        v[2, :] = v[3, :] + [box[0, 0], 0]
        center = [np.mean(v[:, 0]), np.mean(v[:, 1]),
                  0]  # geometric center of box

        bounds = path.Path(v)  # create a path tracing the vertices, v

        angle = np.arccos(box[1, 1] / box[0, 0])  # angle of monoclinic box
        if box[1, 0] < 0:  # the case of an obtuse angle
            angle += np.pi / 2

        m = (v[3, 1] - v[0, 1]) / (
            v[3, 0] - v[0, 0]
        )  # slope from points connecting first and fourth vertices

        # shift = transform.translate(z, before, center)
        #
        # put_in_box(pt, box[0, 0], box[1, 1], m, angle)

        # find z positions, in between which solute will be placed
        lower = 0
        while pts[lower, 2] < z:
            lower += 1

        upper = pts.shape[0] - 1
        while pts[upper, 2] > z:
            upper -= 1

        limits = np.zeros([2, 3])
        limits[0, :] = pts[lower, :]
        limits[1, :] = pts[upper, :]

        shift = transform.translate(
            limits, limits[0, :],
            center)  # shift limits to geometric center of unit cell
        shift[:, 2] = [limits[0, 2], limits[1, 2]]  # keep z positions the same

        for i in range(
                shift.shape[0]
        ):  # check if the points are within the bounds of the unitcell
            if not bounds.contains_point(shift[i, :2]):
                shift[i, :] = put_in_box(shift[i, :], box[0, 0], box[1, 1], m,
                                         angle)

        # Use parametric representation of line between upper and lower points to find the xy value where z is satsified
        v = shift[1, :] - shift[0, :]  # direction vector

        t = (z - shift[0, 2]) / v[2]  # solve for t since we know z
        x = shift[0, 0] + t * v[0]
        y = shift[0, 1] + t * v[1]

        place = np.zeros([1, 3])
        place[0, :] = [x, y, 0]
        place = transform.translate(place, center,
                                    limits[0, :])  # put xy coordinate back
        place[0, 2] = z

        if not bounds.contains_point(
                place[0, :]):  # make sure everything is in the box again
            place[0, :] = put_in_box(place[0, :], box[0, 0], box[1, 1], m,
                                     angle)

        return place[0, :]
Exemple #6
0
def trace_pores(pos, box, layers):
    """
    Find the line which traces through the center of the pores
    :param pos: positions of atoms used to define pore location (args.ref) [natoms, 3]
    :param box: xy box vectors, [2, 2], mdtraj format
    :param layers: number of layers
    :return: points which trace the pore center
    """

    atoms_p_pore = int(pos.shape[0] / 4)  # atoms in each pore
    atoms_p_layer = int(atoms_p_pore / layers)  # atom per layer

    v = np.zeros([4, 2])  # vertices of unitcell box
    v[0, :] = [0, 0]
    v[1, :] = [box[0, 0], 0]
    v[3, :] = [box[1, 0], box[1, 1]]
    v[2, :] = v[3, :] + [box[0, 0], 0]

    center = [np.mean(v[:, 0]), np.mean(v[:, 1]), 0]  # geometric center of box
    bounds = path.Path(v)  # create a path tracing the vertices, v

    angle = np.arccos(box[1, 1] / box[0, 0])  # angle of monoclinic box
    if box[1, 0] < 0:  # the case of an obtuse angle
        angle += np.pi / 2

    m = (v[3, 1] - v[0, 1]) / (
        v[3, 0] - v[0, 0]
    )  # slope from points connecting first and third vertices

    centers = np.zeros([4 * layers, 3])

    for p in range(4):
        pore = pos[
            p * atoms_p_pore:(p + 1) *
            atoms_p_pore, :]  # coordinates for atoms belonging to a single pore
        for l in range(layers):
            before = pore[
                l * atoms_p_layer, :]  # choose the first atom as a reference

            shift = transform.translate(
                pore[l * atoms_p_layer:(l + 1) * atoms_p_layer, :], before,
                center)  # shift everything to towards the center

            for i in range(
                    shift.shape[0]
            ):  # check if the points are within the bounds of the unitcell
                if not bounds.contains_point(shift[i, :2]):
                    shift[i, :] = put_in_box(
                        shift[i, :], box[0, 0], box[1, 1], m,
                        angle)  # if its not in the unitcell, shift it so it is

            c = np.zeros([1, 3])
            c[0, :] = [
                np.mean(shift[:, 0]),
                np.mean(shift[:, 1]),
                np.mean(shift[:, 2])
            ]  # geometric center of reference atoms in this layer

            centers[p * layers + l, :] = transform.translate(
                c, center, before)  # move everything back to where it was

            if not bounds.contains_point(centers[
                    p *
                    layers, :]):  # make sure everything is in the box again
                centers[p * layers + l, :] = put_in_box(
                    centers[p * layers + l, :], box[0, 0], box[1, 1], m, angle)

    return centers
Exemple #7
0
def trace_pores(pos, box, npoints, npores=4, progress=True):
    """
    Find the line which traces through the center of the pores
    :param pos: positions of atoms used to define pore location (args.ref) [natoms, 3]
    :param box: xy box vectors, [2, 2], mdtraj format
    :param npoints: number of points for spline in each pore
    :param npores: number of pores in unit cell (assumed that atoms are number sequentially by pore. i.e. pore 1 atom
    numbers all precede those in pore 2)
    :param progress: set to True if you want a progress bar to be shown

    :return: points which trace the pore center
    """

    single_frame = False
    if np.shape(pos.shape)[0] == 2:
        pos = pos[np.newaxis,
                  ...]  # add a new axis if we are looking at a single frame
        box = box[np.newaxis, ...]
        single_frame = True

    nframes = pos.shape[0]
    atoms_p_pore = int(pos.shape[1] / npores)  # atoms in each pore

    v = np.zeros([nframes, 4, 2])  # vertices of unitcell box
    bounds = []

    v[:, 0, :] = [0, 0]
    v[:, 1, 0] = box[:, 0, 0]
    v[:, 3, :] = np.vstack((box[:, 1, 0], box[:, 1, 1])).T
    v[:, 2, :] = v[:, 3, :] + np.vstack((box[:, 0, 0], np.zeros([nframes]))).T
    center = np.vstack((np.mean(v[..., 0],
                                axis=1), np.mean(v[..., 1],
                                                 axis=1), np.zeros(nframes))).T

    for t in range(nframes):
        bounds.append(mplPath.Path(
            v[t, ...]))  # create a path tracing the vertices, v

    angle = np.arcsin(
        box[:, 1, 1] / box[:, 0, 0]
    )  # specific to case where magnitude of x and y box lengths are equal
    angle = np.where(box[:, 1, 0] < 0, angle + np.pi / 2,
                     angle)  # haven't tested this well yet

    m = (v[:, 3, 1] - v[:, 0, 1]) / (
        v[:, 3, 0] - v[:, 0, 0]
    )  # slope from points connecting first and third vertices

    centers = np.zeros([nframes, npores, npoints, 3])
    bin_centers = np.zeros([nframes, npores, npoints])

    for t in tqdm.tqdm(range(nframes), disable=(not progress)):
        for p in range(npores):

            pore = pos[
                t, p * atoms_p_pore:(p + 1) *
                atoms_p_pore, :]  # coordinates for atoms belonging to a single pore

            while np.min(pore[:, 2]) < 0 or np.max(pore[:, 2]) > box[
                    t, 2,
                    2]:  # because cross-linked configurations can extend very far up and down

                pore[:, 2] = np.where(pore[:, 2] < 0,
                                      pore[:, 2] + box[t, 2, 2], pore[:, 2])
                pore[:, 2] = np.where(pore[:, 2] > box[t, 2, 2],
                                      pore[:, 2] - box[t, 2, 2], pore[:, 2])

            _, bins = np.histogram(pore[:, 2], bins=npoints)  # bin z-positions

            section_indices = np.digitize(
                pore[:, 2],
                bins)  # list that tells which bin each atom belongs to
            bin_centers[t, p, :] = [(bins[i] + bins[i + 1]) / 2
                                    for i in range(npoints)]

            for l in range(1, npoints + 1):

                atom_indices = np.where(section_indices == l)[0]

                before = pore[
                    atom_indices[0], :]  # choose the first atom as a reference

                shift = transform.translate(
                    pore[atom_indices, :], before,
                    center[t, :])  # shift everything to towards the center

                for i in range(
                        shift.shape[0]
                ):  # check if the points are within the bounds of the unitcell
                    if not bounds[t].contains_point(shift[i, :2]):
                        shift[i, :] = put_in_box(
                            shift[i, :], box[t, 0, 0], box[t, 1,
                                                           1], m[t], angle[t]
                        )  # if its not in the unitcell, shift it so it is

                c = [np.mean(shift, axis=0)]

                centers[t, p, l - 1, :] = transform.translate(
                    c, center[t, :],
                    before)  # move everything back to where it was

                if not bounds[t].contains_point(centers[
                        t, p,
                        l - 1, :]):  # make sure everything is in the box again
                    centers[t, p,
                            l - 1, :] = put_in_box(centers[t, p, l - 1, :],
                                                   box[t, 0, 0], box[t, 1, 1],
                                                   m[t], angle[t])

    if single_frame:
        return centers[0, ...]  # doesn't return bin center yet
    else:
        return centers, bin_centers