 Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 """  Handling of Hermite Normal Form matrices  """    import numpy as np  from .smith_normal_form import SmithNormalForm      class HermiteNormalForm(object):  """  Hermite Normal Form matrix.  """    def __init__(self, H, rotations, translations, basis_shifts):  self.H = H  self.snf = SmithNormalForm(H)  self.transformations = []  self.compute_transformations(rotations, translations, basis_shifts)    def compute_transformations(self, rotations, translations, basis_shifts,  tol=1e-3):  """  Save transformations (based on rotations) that turns the supercell  into an equivalent supercell. Precompute these transformations,  consisting of permutation as well as translation and basis shift, for  later use.    Parameters  ----------  rotations : list of ndarrays  translations : list of ndarrays  basis_shifts : ndarray  """    for R, T, basis_shift in zip(rotations, translations,  basis_shifts):  check = np.dot(np.dot(np.linalg.inv(self.H), R), self.H)  check = check - np.round(check)  if (abs(check) < tol).all():  LRL = np.dot(self.snf.L, np.dot(R, np.linalg.inv(self.snf.L)))    # Should be an integer matrix  assert (abs(LRL - np.round(LRL)) < tol).all()  LRL = np.round(LRL).astype(np.int64)  LT = np.dot(T, self.snf.L.T)  self.transformations.append([LRL, LT, basis_shift])      def yield_hermite_normal_forms(det, pbc):  """  Yield all Hermite Normal Form matrices with determinant det.    Parameters  ----------  det : int  Target determinant of HNFs  pbc : list of bools  Periodic boundary conditions of the primitive structure    Yields  ------  ndarray  3x3 HNF matrix  """    # 1D  if sum(pbc) == 1:  hnf = np.eye(3, dtype=int)  69 ↛ 73line 69 didn't jump to line 73, because the loop on line 69 didn't complete for i, bc in enumerate(pbc):  if bc:  hnf[i, i] = det  break  yield hnf    # 2D  elif sum(pbc) == 2:  for a in range(1, det + 1):  if det % a == 0:  c = det // a  for b in range(0, c):  81 ↛ 82line 81 didn't jump to line 82, because the condition on line 81 was never true if not pbc:  hnf = [[1, 0, 0],  [0, a, 0],  [0, b, c]]  85 ↛ 86line 85 didn't jump to line 86, because the condition on line 85 was never true elif not pbc:  hnf = [[a, 0, 0],  [0, 1, 0],  [b, 0, c]]  else:  hnf = [[a, 0, 0],  [b, c, 0],  [0, 0, 1]]  yield np.array(hnf)    # 3D  else:  for a in range(1, det + 1):  if det % a == 0:  for c in range(1, det // a + 1):  if det // a % c == 0:  f = det // (a * c)  for b in range(0, c):  for d in range(0, f):  for e in range(0, f):  hnf = [[a, 0, 0],  [b, c, 0],  [d, e, f]]  yield np.array(hnf)      def yield_reduced_hnfs(ncells, symmetries, pbc, tol=1e-3):  """  For a fixed determinant N (i.e., a number of atoms N), yield all  Hermite Normal Forms (HNF) that are inequivalent under symmetry  operations of the parent lattice.'    Parameters  ----------  N : int  Determinant (or, equivalently, the number of atoms) of the HNF.  symmetries : dict of lists  Symmetry operations of the parent lattice.  pbc : list of bools  Periodic boundary conditions of the primitive structure    Yields  ------  list of ndarrays  Symmetrically inequivalent HNFs with determinant N.  """  rotations = symmetries['rotations']  translations = symmetries['translations']  basis_shifts = symmetries['basis_shifts']  hnfs = []    for hnf in yield_hermite_normal_forms(ncells, pbc):    # Throw away HNF:s that yield equivalent supercells  hnf_inv = np.linalg.inv(hnf)  duplicate = False  for R in rotations:  HR = np.dot(hnf_inv, R)  for hnf_previous in hnfs:  check = np.dot(HR, hnf_previous.H)  check = check - np.round(check)  if (abs(check) < tol).all():  duplicate = True  break  if duplicate:  break  if duplicate:  continue    # If it's not a duplicate, save the hnf  # and the supercell so that it can be compared to  hnf = HermiteNormalForm(hnf, rotations, translations, basis_shifts)  hnfs.append(hnf)  yield hnf