CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
PrimGrid.cc
Go to the documentation of this file.
2 
3 #include <iostream>
4 #include <cmath>
5 #include <cassert>
6 
10 
14 
15 namespace CASM {
16  PrimGrid::PrimGrid(const Lattice &p_lat, const Lattice &s_lat, Index NB) {
17  m_lat[PRIM] = &p_lat;
18  m_lat[SCEL] = &s_lat;
19 
20  m_NB = NB;
21 
22  Eigen::Matrix3d dtrans_mat(p_lat.lat_column_mat().inverse()*s_lat.lat_column_mat());
23 
24  for(int i = 0; i < 3; i++) {
25  for(int j = 0; j < 3; j++) {
26  m_trans_mat(i, j) = round(dtrans_mat(i, j));
27  }
28  }
29  if(m_trans_mat.determinant() == 0) {
30  std::cerr << "CRITICAL ERROR: Attempting to construct a PrimGrid for a superlattice that is smaller than lattice passed as its prim.\n"
31  << "floating-point transformation matrix:\n" << dtrans_mat << "\n was rounded to integer matrix:\n" << m_trans_mat << "\n\n"
32  << "This usage of PrimGrid is not supported. Exiting...\n";
33  assert(0);
34  exit(1);
35  }
36  /*
37  std::cerr << "prim_lat is:\n";
38  m_lat[PRIM]->print(std::cerr);
39  std::cerr << '\n';
40 
41  std::cerr << "scel_lat is:\n";
42  m_lat[SCEL]->print(std::cerr);
43  std::cerr << '\n';
44 
45  std::cerr << "dtrans_mat is\n" << dtrans_mat << '\n';
46  */
47  matrix_type Smat, V;
49 
50  m_invU = inverse(m_U);
51 
52  m_S = Smat.diagonal();
53 
54  //std::cerr << "Smith decomposition is:\n";
55  //std::cerr << m_U << "\n\n" << Smat << "\n\n" << V << "\n\n";
56  m_stride[0] = m_S[0];
57  m_stride[1] = m_S[0] * m_S[1];
58  m_N_vol = m_S[0] * m_S[1] * m_S[2];
59 
60  m_trans_mat = m_U * Smat * V;
61 
62  Smat(0, 0) = m_N_vol / Smat(0, 0);
63  Smat(1, 1) = m_N_vol / Smat(1, 1);
64  Smat(2, 2) = m_N_vol / Smat(2, 2);
65  m_plane_mat = inverse(V) * Smat * inverse(m_U);
66 
67  /*
68  std::cerr << "trans_mat is:\n" << m_trans_mat << "\n\nplane_mat is:\n" << m_plane_mat << "\n\n";
69 
70  std::cerr << "Testing PrimGrid:\n"
71  << "UnitCellCoords:\n";
72  for(int i = 0; i < size(); i++)
73  std::cerr << uccoord(i);
74 
75  std::cerr << "\n\nSupercell Coordinates:\n";
76  for(int i = 0; i < size(); i++)
77  std::cerr << coord(i, SCEL)(FRAC) << '\n';
78  std::cerr << "\n";
79  */
80  }
81 
82  //**********************************************************************************************
83  // Constructor for forcing specific choice of 'U' matrix. Use only in very specific cases (such as applying symmetry to a PrimGrid
85  const Lattice &s_lat,
86  const Eigen::Ref<const PrimGrid::matrix_type> &U,
87  const Eigen::Ref<const PrimGrid::matrix_type> &Smat,
88  Index NB) : m_U(U) {
89  m_lat[PRIM] = &p_lat;
90  m_lat[SCEL] = &s_lat;
91 
92  m_NB = NB;
93 
94  Eigen::Matrix3d dtrans_mat(p_lat.lat_column_mat().inverse()*s_lat.lat_column_mat());
95 
96  for(int i = 0; i < 3; i++) {
97  for(int j = 0; j < 3; j++) {
98  m_trans_mat(i, j) = round(dtrans_mat(i, j));
99  }
100  }
101 
102  if(m_trans_mat.determinant() == 0) {
103  std::cerr << "CRITICAL ERROR: Attempting to construct a PrimGrid for a superlattice that is smaller than lattice passed as its prim.\n"
104  << "floating-point transformation matrix:\n" << dtrans_mat << "\n was rounded to integer matrix:\n" << m_trans_mat << "\n\n"
105  << "This usage of PrimGrid is not supported. Exiting...\n";
106  assert(0);
107  exit(1);
108  }
109 
110  m_invU = inverse(m_U);
111 
112  for(int i = 0; i < 3; i++) {
113  m_S[i] = Smat(i, i);
114  }
115 
116  //std::cerr << "Smith decomposition is:\n";
117  m_stride[0] = m_S[0];
118  m_stride[1] = m_S[0] * m_S[1];
119  m_N_vol = m_S[0] * m_S[1] * m_S[2];
120 
122 
123  /*
124  std::cerr << "trans_mat is:\n" << m_trans_mat << "\n\nplane_mat is:\n" << m_plane_mat << "\n\n";
125 
126  std::cerr << "Testing PrimGrid:\n"
127  << "UnitCellCoords:\n";
128  for(int i = 0; i < size(); i++)
129  std::cerr << uccoord(i);
130 
131  std::cerr << "\n\nSupercell Coordinates:\n";
132  for(int i = 0; i < size(); i++)
133  std::cerr << coord(i, SCEL)(FRAC) << '\n';
134  std::cerr << "\n";
135  */
136  }
137 
138  //**********************************************************************************************
139 
140  const Eigen::DiagonalWrapper<const PrimGrid::vector_type> PrimGrid::matrixS()const {
141  return m_S.asDiagonal();
142  }
143  //**********************************************************************************************
144  Index PrimGrid::find(const Coordinate &_coord) const {
145 
146  auto lambda = [](double val) {
147  return floor(val);
148  };
149  UnitCellCoord bijk(-1, ((((m_lat[PRIM]->inv_lat_column_mat())*_coord.cart()).array() + TOL).unaryExpr(lambda)).matrix().cast<long>());
150 
151  return find(bijk);
152  }
153 
154  //**********************************************************************************************
155 
156  Index PrimGrid::find(const UnitCell &_unitcell) const {
157  return find(UnitCellCoord(-1, _unitcell));
158  }
159 
160  //**********************************************************************************************
161 
162  Index PrimGrid::find(const UnitCellCoord &bijk) const {
163 
164  UnitCellCoord bmnp = to_canonical(get_within(bijk));
165 
166  return bmnp[1] + bmnp[2] * m_stride[0] + bmnp[3] * m_stride[1];
167  }
168 
169  //**********************************************************************************************
170 
171  Index PrimGrid::find_cart(const Eigen::Ref<const Eigen::Vector3d> &_cart_coord) const {
172  return find(Coordinate(_cart_coord, *m_lat[PRIM], CART));
173  }
174 
175  //**********************************************************************************************
176 
199 
201 
202  vector_type vec2 = m_plane_mat * bijk.unitcell();
203 
204  vec2[0] = ((vec2[0] % m_N_vol) + m_N_vol) % m_N_vol;
205  vec2[1] = ((vec2[1] % m_N_vol) + m_N_vol) % m_N_vol;
206  vec2[2] = ((vec2[2] % m_N_vol) + m_N_vol) % m_N_vol;
207 
208  return UnitCellCoord(bijk[0], (m_trans_mat * vec2) / m_N_vol);
209  }
210 
211  //**********************************************************************************************
212 
213  Coordinate PrimGrid::coord(const UnitCellCoord &bijk, CELL_TYPE lat_mode)const {
214 
215  Coordinate tcoord(bijk.unitcell().cast<double>(), *(m_lat[PRIM]), FRAC);
216 
217  tcoord.set_lattice(*(m_lat[lat_mode]), CART);
218  return tcoord;
219  }
220 
221  //**********************************************************************************************
222 
224  return coord(uccoord(l), lat_mode);
225  }
226 
227  //**********************************************************************************************
228 
230  return uccoord(i).unitcell();
231  }
232 
233  //**********************************************************************************************
234 
236  assert(i >= 0 && i < m_N_vol && "PrimGrid::uccoord(Index i) -> index 'i' out of range!");
237 
238  UnitCellCoord bmnp(-1,
239  (i % m_stride[1]) % m_stride[0],
240  (i % m_stride[1]) / m_stride[0],
241  i / m_stride[1]);
242  return from_canonical(bmnp);
243  }
244 
245  //**********************************************************************************************
246 
248 
249  SymGroupRepID perm_rep_ID = group.add_empty_representation();
250  PrimGrid::matrix_type mat_mnp;
251  UnitCellCoord mnp_shift;
252  Index old_l, new_l;
253  for(Index ng = 0; ng < group.size(); ng++) {
254  SymBasisPermute const *rep = group[ng].get_basis_permute_rep(basis_permute_ID);
255  if(!rep) {
256  std::cerr << "CRITICAL ERROR: In PrimGrid::make_permutation_representation, BasisPermute representation is incorrectly initialized!\n"
257  << " basis_permute_ID is " << basis_permute_ID << " and op index is " << group[ng].index() << "\n"
258  << " Exiting...\n";
259 
260  exit(1);
261  }
262 
263  mat_mnp = m_invU * rep->matrix() * m_U;
264 
265  std::vector<UnitCellCoord> const &b_permute = rep->data();
266 
267  Array<Index> ipermute(b_permute.size()*size());
268  //std::cerr << "PRINTING b_permute array for op " << ng << ":\n";
269  //begin loop over sites
270  for(Index nb = 0; nb < b_permute.size(); nb++) {
271  //std::cerr << b_permute.at(nb) << '\n';
272  mnp_shift = to_canonical(b_permute.at(nb));
273 
274  vector_type old_mnp, new_mnp;
275  EigenCounter<vector_type> mnp_count(vector_type::Zero(), m_S - vector_type::Ones(), vector_type::Ones());
276  for(; mnp_count.valid(); ++mnp_count) {
277  new_mnp = mat_mnp * mnp_count() + mnp_shift.unitcell();
278 
279  //map within bounds
280  for(int i = 0; i < 3; i++) {
281  new_mnp[i] = ((new_mnp[i] % m_S[i]) + m_S[i]) % m_S[i];
282  }
283 
284  old_l = mnp_count[0] + mnp_count[1] * m_stride[0] + mnp_count[2] * m_stride[1] + nb * size();
285  new_l = new_mnp[0] + new_mnp[1] * m_stride[0] + new_mnp[2] * m_stride[1] + mnp_shift[0] * size();
286  assert(old_l < b_permute.size()*size() && new_l < b_permute.size()*size());
287  // We have found uccoord(new_l) = symop*uccoord(old_l) -- this describes how indexing of the uccoordinates change
288  // However, the indexing of the uccoords remains fixed, and we want to describe the permutation of something *at* the sites,
289  // like an occupation bit. So if uccord(old_l) transforms into uccoord(new_l), we know that the object originally at 'new_l'
290  // was effectively transformed into the object that was originally at 'old_l'. (in other words, the objects permute inversely to the labels)
291  // i.e., new_occ(new_l) = old_occ(old_l) --> this matches our permutation convention, which is specified as
292  // new_occ(new_l) = old_occ(ipermute[new_l])
293  // and thus:
294  ipermute[new_l] = old_l;
295  }
296  }//end loop over sites
297  //std::cerr << "\\end " << ng << '\n';
298  group[ng].set_rep(perm_rep_ID, SymPermutation(ipermute));
299  }
300  return perm_rep_ID;
301  }
302 
303  //**********************************************************************************************
304  // for Array<Array<int> > perms=prim_grid.make_translation_permutations(NB);
305  // perms[l] is the Supercell permutation that results when sites are translated by
306  // prim_grid.uccoord(l). In other words, site 'l' is translated so that (i,j,k)=(0,0,0)
307 
309  Array<Permutation > perms;
310  perms.reserve(size());
311  Array<Index> ipermute(NB * size(), 0);
312  UnitCellCoord shift_bmnp, bmnp;
313  //std::cerr << "In PrimGrid::make_translation_permutations:\n";
314  Index new_l;
315  for(Index shift_l = 0; shift_l < size(); shift_l++) {
316  //shift_bmnp describes translation by uccoord(shift_l)
317  shift_bmnp[1] = (shift_l % m_stride[1]) % m_stride[0];
318  shift_bmnp[2] = (shift_l % m_stride[1]) / m_stride[0];
319  shift_bmnp[3] = shift_l / m_stride[1];
320  //std::cerr << "shift_bmnp " << shift_l << " is " << shift_bmnp;
321  for(Index old_l = 0; old_l < size(); old_l++) {
322  bmnp[1] = (old_l % m_stride[1]) % m_stride[0];
323  bmnp[2] = (old_l % m_stride[1]) / m_stride[0];
324  bmnp[3] = old_l / m_stride[1];
325  //std::cerr << "old_bmnp " << old_l << " is " << bmnp;
326 
327  bmnp[1] = (bmnp[1] + shift_bmnp[1]) % m_S[0];
328  bmnp[2] = (bmnp[2] + shift_bmnp[2]) % m_S[1];
329  bmnp[3] = (bmnp[3] + shift_bmnp[3]) % m_S[2];
330 
331  //std::cerr << "new_bmnp " << bmnp[1] + bmnp[2] * m_stride[0] + bmnp[3] * m_stride[1] << " is " << bmnp;
332  for(Index nb = 0; nb < NB; nb++) {
333  new_l = bmnp[1] + bmnp[2] * m_stride[0] + bmnp[3] * m_stride[1];
334 
335  // See comments in PrimGrid::make_permutation_representation() above
336  ipermute[new_l + nb * size()] = old_l + nb * size();
337  }
338  }
339  perms.push_back(Permutation(ipermute));
340  }
341  return perms;
342  }
343  // private functions:
344 
345  //**********************************************************************************************
349  UnitCellCoord bmnp(bijk[0], 0, 0, 0);
350  for(int i = 0; i < 3; i++) {
351  for(int j = 0; j < 3; j++) {
352  bmnp[i + 1] += m_invU(i, j) * bijk[j + 1];
353  }
354  //Map within bounds
355  bmnp[i + 1] = ((bmnp[i + 1] % m_S[i]) + m_S[i]) % m_S[i];
356  }
357 
358  return bmnp;
359  }
360 
361  //**********************************************************************************************
365  UnitCellCoord bijk(bmnp[0], 0, 0, 0);
366  for(int i = 0; i < 3; i++) {
367  for(int j = 0; j < 3; j++) {
368  bijk[i + 1] += m_U(i, j) * bmnp[j + 1];
369  }
370  }
371  return get_within(bijk);
372  };
373 
374  //==============================================================================================
376  return SymOp::translation(coord(l, PRIM).cart());
377  }
378 }
379 
int m_stride[2]
Definition: PrimGrid.hh:87
Eigen::Matrix< long, 3, 1 > vector_type
Definition: PrimGrid.hh:33
static SymOp translation(const Eigen::Ref< const vector_type > &_tau)
static method to create operation that describes pure translation
Definition: SymOp.hh:35
long int m_N_vol
Number of primgrid lattice points in the supercell.
Definition: PrimGrid.hh:38
A Counter allows looping over many incrementing variables in one loop.
Definition: Counter.hh:71
Index size() const
Definition: Array.hh:145
Coordinate_impl::CartCoordinate cart()
Set Cartesian coordinate vector and update fractional coordinate vector.
Definition: Coordinate.hh:593
Type-safe ID object for communicating and accessing Symmetry representation info. ...
long int m_NB
Number of basis atoms in the primitive cell.
Definition: PrimGrid.hh:41
void push_back(const T &toPush)
Definition: Array.hh:513
matrix_type m_U
The Smith Normal Form decomposition is: trans_mat = U*S*V, with det(U)=det(V)=1; S is diagonal...
Definition: PrimGrid.hh:49
UnitCellCoord to_canonical(const UnitCellCoord &bijk) const
Definition: PrimGrid.cc:348
matrix_type m_plane_mat
Definition: PrimGrid.hh:46
Unit Cell Coordinates.
SymBasisPermute describes how a symmetry operation permutes atoms in a basis.
Eigen::Matrix< long, 3, 1 > m_S
Definition: PrimGrid.hh:88
Lattice const * m_lat[2]
m_lat[PRIM] is primitive lattice, lat[SCEL] is super lattice
Definition: PrimGrid.hh:35
Main CASM namespace.
Definition: complete.cpp:8
const double TOL
const Eigen::Matrix3d & lat_column_mat() const
3x3 matrix with lattice vectors as its columne
Definition: Lattice.hh:104
Unit Cell Indices.
const Eigen::DiagonalWrapper< const PrimGrid::vector_type > matrixS() const
Definition: PrimGrid.cc:140
Index find(const Coordinate &_coord) const
Definition: PrimGrid.cc:144
SymPermutation describes how a symmetry operation permutes a list of 'things' For example...
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
Definition: SymGroup.hh:33
SymOp is the Coordinate representation of a symmetry operation it keeps fraction (FRAC) and Cartesian...
Definition: SymOp.hh:28
Represents cartesian and fractional coordinates.
Definition: Coordinate.hh:34
SymGroupRepID make_permutation_representation(const SymGroup &group, SymGroupRepID basis_permute_rep) const
Definition: PrimGrid.cc:247
const std::vector< UnitCellCoord > & data() const
Get underlying data (data()[b] is the result of transforming (b,0,0,0))
UnitCellCoord get_within(const UnitCellCoord &_uccoord) const
Definition: PrimGrid.cc:200
Eigen::Matrix< typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > adjugate(const Eigen::MatrixBase< Derived > &M)
Return adjugate matrix.
EigenIndex Index
For long integer indexing:
Index size() const
Definition: PrimGrid.hh:108
Eigen::Matrix< typename Derived::Scalar, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > inverse(const Eigen::MatrixBase< Derived > &M)
Return the integer inverse matrix of an invertible integer matrix.
UnitCell & unitcell()
void set_lattice(const Lattice &new_lat, COORD_TYPE mode)
Change the home lattice of the coordinate, selecting one representation (either CART or FRAC) that re...
Definition: Coordinate.cc:245
SymOp sym_op(Index l) const
Definition: PrimGrid.cc:375
ReturnArray< Permutation > make_translation_permutations(Index NB) const
Definition: PrimGrid.cc:308
Eigen::Matrix3d Matrix3d
void reserve(Index new_max)
Definition: Array.hh:491
Eigen::Matrix< long, 3, 3 > matrix_type
Definition: PrimGrid.hh:32
void smith_normal_form(const Eigen::MatrixBase< DerivedIn > &M, Eigen::MatrixBase< DerivedOut > &U, Eigen::MatrixBase< DerivedOut > &S, Eigen::MatrixBase< DerivedOut > &V)
Return the smith normal form, M == U*S*V.
matrix_type m_trans_mat
Definition: PrimGrid.hh:46
PrimGrid(const Lattice &p_lat, const Lattice &s_lat, Index NB=1)
Definition: PrimGrid.cc:16
UnitCellCoord uccoord(Index i) const
Definition: PrimGrid.cc:235
Coordinate coord(Index l, CELL_TYPE lat_mode) const
Definition: PrimGrid.cc:223
UnitCell unitcell(Index i) const
Definition: PrimGrid.cc:229
const Eigen::Matrix3l & matrix() const
Get underlying integer transformation amtrix.
matrix_type m_invU
Definition: PrimGrid.hh:49
SymGroupRepID add_empty_representation() const
Add a new empty representation.
Definition: SymGroup.cc:3109
Index find_cart(const Eigen::Ref< const Eigen::Vector3d > &_cart_coord) const
Definition: PrimGrid.cc:171
UnitCellCoord from_canonical(const UnitCellCoord &bmnp) const
Definition: PrimGrid.cc:364
int round(double val)
Definition: CASM_math.cc:6