Beispiel #1
0
def periodicVoronoiCell(a=1.3968418,
                        L=numpy.array([10, 10]),
                        N=10,
                        cType='tr',
                        **kwargs):
    """
    Returns a cell of size L with N grains made according to the voronoi constructions.
    The positions and orientations of the grains are random.
    """

    # Get origins
    if 'x0' not in kwargs:
        x0, y0 = ptsInBox(N, L)
    else:
        x0 = kwargs['x0']
        y0 = kwargs['y0']
        N = len(x0)
    # Get a list of axes
    ax = kwargs.get('axes', randomAxes(N))
    z0 = numpy.zeros(N)
    # Repeat for double periodic geometry
    ax = ax * 9  # Repeat 9 times
    x, y, z = [], [], []
    for i in [0, -1, 1]:
        for j in [0, -1, 1]:
            x.extend(x0 + L[0] * i)
            y.extend(y0 + L[1] * j)
            z.extend(z0)

    x, y, z = numpy.array(x), numpy.array(y), numpy.array(z)
    orgs = numpy.concatenate(
        (x.reshape(N * 9, 1), y.reshape(N * 9, 1), z.reshape(N * 9, 1)),
        axis=1)

    # Get the number of repeats needed for the crystals
    D = numpy.linalg.norm(L) * 3  # Diagonal of the periodic box
    r = (int(D / a) + 2) * 2  # repeats
    rc = rotatedCrystal(numpy.eye(3), size=(r, r, 1), a=a, cType=cType)
    rc.positions[:, 2] = 0
    orgPos = rc.positions

    # ---- Find the grain boundaries with a voronoi tesselation
    # ---- we do this to mark the atoms near the grain boundary.
    centers = numpy.zeros((len(x), 2))
    centers[:, 0], centers[:, 1] = x, y
    vor = Voronoi(centers)
    edges = vorEdges(vor, D)

    # positions = []	# positions of the atoms in the cell
    bulkPositions = numpy.ndarray(
        shape=(0, 3))  # positions of the bulk atoms in the cell
    gbPositions = numpy.ndarray(
        shape=(0, 3))  # positions of the grain boundary atoms in the cell
    unRatPositions = numpy.ndarray(
        shape=(0, 3))  # positions of the unrattlable atoms in the cell
    padPositions = numpy.ndarray(
        shape=(0, 3))  # positions of the pad atoms in the cell

    tags = numpy.ndarray(
        shape=(0, 1)
    )  # tags of the atoms 0 = bulk, 1 = grain boundary, 2 = pad region, 3 = unrattlable
    gn = 0
    overlap = kwargs.get('overlap', 0.5)
    for v, x1, y1, z1 in zip(ax, x0, y0, z0):
        gn += 1
        p0 = numpy.array([x1, y1, z1])
        p = copy.copy(orgPos)
        p = numpy.dot(v, p.T).T
        p += p0  # Center the crystal at the center of the grain
        # Choose all in the big box
        p = p[numpy.logical_and(*[
            numpy.logical_and(p[:, i] > -L[i], p[:, i] <= 2 * L[i])
            for i in range(2)
        ])]

        # Find the grain number to which we are closest
        # allDist = cdist(p, orgs, 'euclidean')
        # gNum = numpy.argmin(allDist,axis=1)

        if overlap == 0:
            # Find gNum with c routine
            gNum = numpy.zeros(len(p))
            _cPolyUtils.closest(p[:, 0], p[:, 1], orgs[:, 0], orgs[:, 1], gNum)
            gNum = gNum.astype(int)

            p = p[gNum == gn - 1]  # Choose all that belong to the grain
        else:
            # finite overlap means we need to use voronoi edges to determine which points lie within an overlap region
            # voronoi region associated with the point
            reg = vor.regions[vor.point_region[
                gn - 1]]  # region associated with the point
            if -1 in reg:
                raise Exception('Open region associated with generator')
            nVerts = len(reg)  # number of verticies in the region

            p = pointsInRegion(gn - 1, vor, p, overlap=overlap)

        # Correct for periodic boundaries
        for i in range(2):
            p[p[:, i] < 0, i] += L[i]
            p[p[:, i] >= L[i], i] -= L[i]
        # Find a strip close to the grain boundary
        t = numpy.zeros(len(p)).reshape((len(p), 1))  # Default tag bulk
        bWidth = kwargs.get('bWidth', 10.0)
        pad = kwargs.get('pad', 5.0)
        ratPad = kwargs.get('ratPad', 2.0)
        for edge in edges:
            # for edge in pt2edge[(x1,y1,z1)]:
            p1, p2, slope = [numpy.ndarray((1, 3)) * 0 for i in range(3)]
            p1[:, :2], p2[:, :2], slope[:, :2] = edge['p1'], edge['p2'], edge[
                't']

            # The library sometimes returns nan due to the 2d nature of the problem. Reset it.
            slope[:, 2] = 0
            p1[:, 2] = 0
            p2[:, 2] = 0

            proj1, proj2 = numpy.dot(p - p1,
                                     slope.T), numpy.dot(p - p2, slope.T)
            distToEdge = (numpy.sum(((p1 - p) + proj1 * slope)**2.0,
                                    axis=1)**0.5).reshape((len(p), 1))
            # tag pad region
            t[numpy.logical_and(
                numpy.logical_and(t != 1, t != 3),
                numpy.logical_and(
                    numpy.logical_and(distToEdge < bWidth + pad,
                                      distToEdge >= bWidth),
                    proj1 * proj2 < 0))] = 2
            # tag unrattlable
            t[numpy.logical_and(
                t != 1,
                numpy.logical_and(
                    numpy.logical_and(distToEdge < bWidth,
                                      distToEdge > bWidth - ratPad),
                    proj1 * proj2 < 0))] = 3
            # tag grain boundary
            t[numpy.logical_and(distToEdge <= bWidth - ratPad,
                                proj1 * proj2 < 0)] = 1
        bulkPositions = numpy.concatenate((bulkPositions, p[(t == 0)[:,
                                                                     0], :]))
        padPositions = numpy.concatenate((padPositions, p[(t == 2)[:, 0], :]))
        unRatPositions = numpy.concatenate((unRatPositions, p[(t == 3)[:,
                                                                       0], :]))

        # Filter out 'close' atoms in grain boundary
        cutoff = kwargs.get('cutoff', 0.2)
        thisGB = p[(t == 1)[:, 0], :]
        if len(gbPositions) > 0:
            # gbDist = cdist(thisGB,gbPositions)
            # minDist = numpy.min(gbDist,axis=1)

            # Find minDist with c routine
            minInd = numpy.zeros(len(thisGB)).astype('int')
            _cPolyUtils.closest(thisGB[:, 0], thisGB[:, 1], gbPositions[:, 0],
                                gbPositions[:, 1], minInd)
            minDist = numpy.sum((thisGB - gbPositions[minInd])**2.0,
                                axis=1)**0.5

            thisGB = numpy.delete(thisGB,
                                  numpy.where(minDist < a * cutoff),
                                  axis=0)
        gbPositions = numpy.concatenate((gbPositions, thisGB))

    # Filter out close atoms in the gb again; possible to have anamolies due to multiple grain overlap
    cutoff = kwargs.get('cutoff', 0.2)
    if len(gbPositions) > 0:
        closeAtoms = True
        while closeAtoms:
            # Find minDist with c routine
            minInd = numpy.zeros(len(gbPositions) - 1)
            minDist = numpy.zeros(len(gbPositions) - 1)
            _cPolyUtils.selfClosest(L[0], L[1], gbPositions[:, 0],
                                    gbPositions[:, 1], minInd, minDist)

            gbPositions = numpy.delete(gbPositions,
                                       numpy.where(minDist < cutoff * a),
                                       axis=0)

            minInd = numpy.zeros(len(gbPositions) - 1)
            minDist = numpy.zeros(len(gbPositions) - 1)
            _cPolyUtils.selfClosest(L[0], L[1], gbPositions[:, 0],
                                    gbPositions[:, 1], minInd, minDist)
            if minDist.min() >= cutoff * a:
                closeAtoms = False

    # collect all positions
    positions = numpy.concatenate((bulkPositions, unRatPositions))
    positions = numpy.concatenate((positions, gbPositions))
    positions = numpy.concatenate((positions, padPositions))
    tags = numpy.zeros(len(positions))
    tags[-len(unRatPositions) - len(gbPositions) - len(padPositions):] = 3
    tags[-len(gbPositions) - len(padPositions):] = 1
    tags[-len(padPositions):] = 2

    # Set the gbPositions as rattlable, and then merge the unRat and gb
    rattlable = numpy.zeros(len(tags))
    rattlable[tags == 1] = 1
    tags[tags == 3] = 1

    cell = numpy.diag([L[0], L[1], 10])
    # cr = Atoms(symbols=symbols, positions=positions, cell = cell, pbc=[True,True,True])
    numbers = numpy.ones(len(positions)) * 6
    symbols = ['C'] * len(positions)
    cr = Atoms(numbers=numbers,
               positions=positions,
               cell=cell,
               tags=tags,
               pbc=[True, True, True])
    cr.ax = ax
    cr.centers = centers
    cr.orgs = orgs
    cr.rattlable = rattlable
    if sum(tags == 0) == 0 or sum(tags == 1) == 0 or sum(tags == 2) == 0:
        print "It seems that either the cell is too small or there are too many grains. You might want to fix this"
    return cr
Beispiel #2
0
def periodicVoronoiCell(a=1.3968418, L=numpy.array([10, 10]), N=10, cType='tr', **kwargs):
    """
    Returns a cell of size L with N grains made according to the voronoi constructions.
    The positions and orientations of the grains are random.
    """

    # Get origins
    if 'x0' not in kwargs:
        x0, y0 = ptsInBox(N, L)
    else:
        x0 = kwargs['x0']
        y0 = kwargs['y0']
        N = len(x0)
    # Get a list of axes
    ax = kwargs.get('axes', randomAxes(N))
    z0 = numpy.zeros(N)
    # Repeat for double periodic geometry
    ax = ax * 9  # Repeat 9 times
    x, y, z = [], [], []
    for i in [0, -1, 1]:
        for j in [0, -1, 1]:
            x.extend(x0 + L[0] * i)
            y.extend(y0 + L[1] * j)
            z.extend(z0)

    x, y, z = numpy.array(x), numpy.array(y), numpy.array(z)
    orgs = numpy.concatenate((x.reshape(N * 9, 1), y.reshape(N * 9, 1), z.reshape(N * 9, 1)), axis=1)

    # Get the number of repeats needed for the crystals
    D = numpy.linalg.norm(L) * 3  # Diagonal of the periodic box
    r = (int(D / a) + 2) * 2  # repeats
    rc = rotatedCrystal(numpy.eye(3), size=(r, r, 1), a=a, cType=cType)
    rc.positions[:, 2] = 0
    orgPos = rc.positions

    # ---- Find the grain boundaries with a voronoi tesselation
    # ---- we do this to mark the atoms near the grain boundary.
    centers = numpy.zeros((len(x), 2))
    centers[:, 0], centers[:, 1] = x, y
    vor = Voronoi(centers)
    edges = vorEdges(vor, D)

    # positions = []	# positions of the atoms in the cell
    bulkPositions = numpy.ndarray(shape=(0, 3))  # positions of the bulk atoms in the cell
    gbPositions = numpy.ndarray(shape=(0, 3))  # positions of the grain boundary atoms in the cell
    unRatPositions = numpy.ndarray(shape=(0, 3))  # positions of the unrattlable atoms in the cell
    padPositions = numpy.ndarray(shape=(0, 3))  # positions of the pad atoms in the cell

    tags = numpy.ndarray(
        shape=(0, 1))  # tags of the atoms 0 = bulk, 1 = grain boundary, 2 = pad region, 3 = unrattlable
    gn = 0
    overlap = kwargs.get('overlap', 0.5)
    for v, x1, y1, z1 in zip(ax, x0, y0, z0):
        gn += 1
        p0 = numpy.array([x1, y1, z1])
        p = copy.copy(orgPos)
        p = numpy.dot(v, p.T).T
        p += p0  # Center the crystal at the center of the grain
        # Choose all in the big box
        p = p[numpy.logical_and(*[numpy.logical_and(p[:, i] > -L[i], p[:, i] <= 2 * L[i]) for i in range(2)])]

        # Find the grain number to which we are closest
        # allDist = cdist(p, orgs, 'euclidean')
        # gNum = numpy.argmin(allDist,axis=1)

        if overlap == 0:
            # Find gNum with c routine
            gNum = numpy.zeros(len(p))
            _cPolyUtils.closest(p[:, 0], p[:, 1], orgs[:, 0], orgs[:, 1], gNum)
            gNum = gNum.astype(int)

            p = p[gNum == gn - 1]  # Choose all that belong to the grain
        else:
            # finite overlap means we need to use voronoi edges to determine which points lie within an overlap region
            # voronoi region associated with the point
            reg = vor.regions[vor.point_region[gn - 1]]  # region associated with the point
            if -1 in reg:
                raise Exception('Open region associated with generator')
            nVerts = len(reg)  # number of verticies in the region

            p = pointsInRegion(gn - 1, vor, p, overlap=overlap)

        # Correct for periodic boundaries
        for i in range(2):
            p[p[:, i] < 0, i] += L[i]
            p[p[:, i] >= L[i], i] -= L[i]
        # Find a strip close to the grain boundary
        t = numpy.zeros(len(p)).reshape((len(p), 1))  # Default tag bulk
        bWidth = kwargs.get('bWidth', 10.0)
        pad = kwargs.get('pad', 5.0)
        ratPad = kwargs.get('ratPad', 2.0)
        for edge in edges:
            # for edge in pt2edge[(x1,y1,z1)]:
            p1, p2, slope = [numpy.ndarray((1, 3)) * 0 for i in range(3)]
            p1[:, :2], p2[:, :2], slope[:, :2] = edge['p1'], edge['p2'], edge['t']

            # The library sometimes returns nan due to the 2d nature of the problem. Reset it.
            slope[:, 2] = 0
            p1[:, 2] = 0
            p2[:, 2] = 0

            proj1, proj2 = numpy.dot(p - p1, slope.T), numpy.dot(p - p2, slope.T)
            distToEdge = (numpy.sum(((p1 - p) + proj1 * slope) ** 2.0, axis=1) ** 0.5).reshape((len(p), 1))
            # tag pad region
            t[numpy.logical_and(numpy.logical_and(t != 1, t != 3),
                                numpy.logical_and(numpy.logical_and(distToEdge < bWidth + pad, distToEdge >= bWidth),
                                                  proj1 * proj2 < 0))] = 2
            # tag unrattlable
            t[numpy.logical_and(t != 1,
                                numpy.logical_and(numpy.logical_and(distToEdge < bWidth, distToEdge > bWidth - ratPad),
                                                  proj1 * proj2 < 0))] = 3
            # tag grain boundary
            t[numpy.logical_and(distToEdge <= bWidth - ratPad, proj1 * proj2 < 0)] = 1
        bulkPositions = numpy.concatenate((bulkPositions, p[(t == 0)[:, 0], :]))
        padPositions = numpy.concatenate((padPositions, p[(t == 2)[:, 0], :]))
        unRatPositions = numpy.concatenate((unRatPositions, p[(t == 3)[:, 0], :]))

        # Filter out 'close' atoms in grain boundary
        cutoff = kwargs.get('cutoff', 0.2)
        thisGB = p[(t == 1)[:, 0], :]
        if len(gbPositions) > 0:
            # gbDist = cdist(thisGB,gbPositions)
            # minDist = numpy.min(gbDist,axis=1)

            # Find minDist with c routine
            minInd = numpy.zeros(len(thisGB)).astype('int')
            _cPolyUtils.closest(thisGB[:, 0], thisGB[:, 1], gbPositions[:, 0], gbPositions[:, 1], minInd)
            minDist = numpy.sum((thisGB - gbPositions[minInd]) ** 2.0, axis=1) ** 0.5

            thisGB = numpy.delete(thisGB, numpy.where(minDist < a * cutoff), axis=0)
        gbPositions = numpy.concatenate((gbPositions, thisGB))

    # Filter out close atoms in the gb again; possible to have anamolies due to multiple grain overlap
    cutoff = kwargs.get('cutoff', 0.2)
    if len(gbPositions) > 0:
        closeAtoms = True
        while closeAtoms:
            # Find minDist with c routine
            minInd = numpy.zeros(len(gbPositions) - 1)
            minDist = numpy.zeros(len(gbPositions) - 1)
            _cPolyUtils.selfClosest(L[0], L[1], gbPositions[:, 0], gbPositions[:, 1], minInd, minDist)

            gbPositions = numpy.delete(gbPositions, numpy.where(minDist < cutoff * a), axis=0)

            minInd = numpy.zeros(len(gbPositions) - 1)
            minDist = numpy.zeros(len(gbPositions) - 1)
            _cPolyUtils.selfClosest(L[0], L[1], gbPositions[:, 0], gbPositions[:, 1], minInd, minDist)
            if minDist.min() >= cutoff * a:
                closeAtoms = False

    # collect all positions
    positions = numpy.concatenate((bulkPositions, unRatPositions))
    positions = numpy.concatenate((positions, gbPositions))
    positions = numpy.concatenate((positions, padPositions))
    tags = numpy.zeros(len(positions))
    tags[-len(unRatPositions) - len(gbPositions) - len(padPositions):] = 3
    tags[-len(gbPositions) - len(padPositions):] = 1
    tags[-len(padPositions):] = 2

    # Set the gbPositions as rattlable, and then merge the unRat and gb
    rattlable = numpy.zeros(len(tags))
    rattlable[tags == 1] = 1
    tags[tags == 3] = 1

    cell = numpy.diag([L[0], L[1], 10])
    # cr = Atoms(symbols=symbols, positions=positions, cell = cell, pbc=[True,True,True])
    numbers = numpy.ones(len(positions)) * 6
    symbols = ['C'] * len(positions)
    cr = Atoms(numbers=numbers, positions=positions, cell=cell, tags=tags, pbc=[True, True, True])
    cr.ax = ax
    cr.centers = centers
    cr.orgs = orgs
    cr.rattlable = rattlable
    if sum(tags == 0) == 0 or sum(tags == 1) == 0 or sum(tags == 2) == 0:
        print "It seems that either the cell is too small or there are too many grains. You might want to fix this"
    return cr