Поверните геометрию так, чтобы ее плоскость соответствовала базовой плоскости

У меня есть трехмерная кристаллическая структура, записанная в декартовых координатах. Уточняю фрезеровку кристалла. Затем эта плоскость Миллера должна выровняться с плоскостью xy системы отсчета.

Более ранняя ветка помогла мне добиться этого. Были предприняты следующие шаги:

  • Определить мельник-самолет
  • Создайте локальную декартову систему отсчета, ориентированную на плоскость Миллера
  • Получите единичные векторы этого локального кадра
  • Возьмите продукт этих единичных векторов с векторами, которые описывают положение атома по сравнению с исходной точкой отсчета.

Указание таких плоскостей Миллера, как (1 0 0), (0 -2 1), (10, 0 1), не проблема и отлично работает. Однако задание плоскости Миллера как (1 1 1) приводит к перекосу кристалла.

Я включил здесь изображение для иллюстрации.

Здесь приведен фрагмент кода, использованный для этой операции. Вызывается MillerRotate. Он возвращает единичные векторы, которые будут использоваться для продукта с векторами координат атомов. Этот inproduct взят в классе Rotate.

class MillerRotate(Rotate):
def __init__(self, indices):
    self.indices = indices

def rotate_func(self, geom):
    data = geom.coordinates
    lattice = np.array([ geom.lattice[0][0], geom.lattice[1][1], geom.lattice[2][2] ])

    if (self.indices == [0,0,0]):
        raise Exception(
                "Cannot rotate 0 0 0")

    # get 3 points at the miller plane    
    a = np.zeros((len(lattice), len(lattice)))
    for i in range(len(lattice)):
        if (self.indices[i] != 0):
            a[i][i] = self.indices[i]*lattice[i]
        else:
            a[i][i] = lattice[i]
            j = self.indices.index(next(filter(lambda x: x!=0, self.indices)))
            a[i][j] = self.indices[j]*lattice[j]

    # compute two vectors to get plane 
    v1 = a[1]-a[0]
    v2 = a[2]-a[0]

    # compute unit vectors
    z = np.cross(v1,v2)
    y = np.cross(v1,z)
    x = np.cross(y ,z)
    z = z/max(z,key=abs)
    y = y/max(y,key=abs)
    x = x/max(x,key=abs)

    # matrix to be taken as inproduct with atom coordinates.
    A = np.array([x, y, z])

    if np.linalg.det(A) < 0.0:
        A[2,:] *= -1.0

    return A

class Rotate(Operation):
'''Generic rotation'''
def __init__(self):
    self.rotate_func = None

def __call__(self, geom):
    data = geom.coordinates
    A = self.rotate_func(geom)
    detA = np.linalg.det(A)
    if detA < 0.0:
        raise Exception("Determinant of Rotation needs to be 1")
    tmp = np.dot(data, A.T)
    data[:] = tmp[:]

0 ответов

Другие вопросы по тегам