CASM  1.1.0
A Clusters Approach to Statistical Mechanics
SymGroup.cc
Go to the documentation of this file.
2 
3 #include "casm/casm_io/Log.hh"
11 #include "casm/misc/CASM_math.hh"
12 #include "casm/misc/algorithm.hh"
14 #include "casm/symmetry/SymInfo.hh"
18 
19 namespace CASM {
20 
21 namespace Local {
22 
23 // count number of operations of each type
24 // proper before improper for each order, in ascending order
25 // [identity, inversion, 2-fold, mirror, 3-fold, improper 3-fold, etc.]
26 static std::vector<Index> _number_of_operation_types(SymGroup const &group) {
27  std::vector<Index> result(20, 0);
28  for (SymOp const &op : group) {
29  SymInfo info(op, group.lattice());
30  if (info.op_type == symmetry_type::identity_op) {
31  result[0]++;
32  } else if (info.op_type == symmetry_type::inversion_op) {
33  result[1]++;
34  } else {
35  Index bit = 0;
36  if (op.matrix().determinant() < 0) bit = 1;
37  for (Index n = 2; n <= 20; ++n) {
38  if ((round(std::abs(info.angle)) * n) % 360 == 0) {
39  result[2 * (n - 1) + bit]++;
40  break;
41  }
42  }
43  }
44  }
45  return result;
46 }
47 
48 // populates point group infor for centric point group (groups with inversion)
49 static std::map<std::string, std::string> _centric_point_group_info(
50  std::vector<Index> const &op_types) {
51  bool is_error = false;
52  std::map<std::string, std::string> result;
53  if (op_types[4] == 4) { // 3-fold
54  result["crystal_system"] = "Cubic";
55  result["international_name"] = "m-3";
56  result["name"] = "Th";
57  result["latex_name"] = "T_h";
58  result["space_group_range"] = "200-206";
59  } else if (op_types[4] == 8) { // 3-fold
60  result["crystal_system"] = "Cubic";
61  result["international_name"] = "m-3m";
62  result["name"] = "Oh";
63  result["latex_name"] = "O_h";
64  result["space_group_range"] = "221-230";
65  } else if (op_types[10] == 2) { // 6-fold
66  result["crystal_system"] = "Hexagonal";
67  if (op_types[2] == 1) { // 2-fold
68  result["international_name"] = "6/m";
69  result["name"] = "C6h";
70  result["latex_name"] = "C_{6h}";
71  result["space_group_range"] = "175-176";
72  } else if (op_types[2] == 7) { // 2-fold
73  result["international_name"] = "6/mmm";
74  result["name"] = "D6h";
75  result["latex_name"] = "D_{6h}";
76  result["space_group_range"] = "191-194";
77  } else {
78  is_error = true;
79  }
80  } // end hexagonal
81  else if (op_types[4] == 2) { // 3-fold
82  result["crystal_system"] = "Rhombohedral";
83  if (op_types[2] == 0) { // 2-fold
84  result["international_name"] = "-3";
85  result["name"] = "S6";
86  result["latex_name"] = "S_6";
87  result["space_group_range"] = "147-148";
88  } else if (op_types[2] == 3) { // 2-fold
89  result["international_name"] = "-3m";
90  result["name"] = "D3d";
91  result["latex_name"] = "D_{3d}";
92  result["space_group_range"] = "162-167";
93  } else {
94  is_error = true;
95  }
96  } // end rhombohedral
97  else if (op_types[6] == 2) { // 4-fold
98  result["crystal_system"] = "Tetragonal";
99  if (op_types[2] == 1) { // 2-fold
100  result["international_name"] = "4/m";
101  result["name"] = "C4h";
102  result["latex_name"] = "C_{4h}";
103  result["space_group_range"] = "83-88";
104  } else if (op_types[2] == 5) { // 2-fold
105  result["international_name"] = "4/mmm";
106  result["name"] = "D4h";
107  result["latex_name"] = "D_{4h}";
108  result["space_group_range"] = "123-142";
109  } else {
110  is_error = true;
111  }
112  } // end tetragonal
113  else if (op_types[2] == 3) {
114  result["crystal_system"] = "Orthorhomic";
115  result["international_name"] = "mmm";
116  result["name"] = "D2h";
117  result["latex_name"] = "D_{2h}";
118  result["space_group_range"] = "47-84";
119  } // end orthorhombic
120  else if (op_types[2] == 1) {
121  result["crystal_system"] = "Monoclinic";
122  result["international_name"] = "2/m";
123  result["name"] = "C2h";
124  result["latex_name"] = "C_{2h}";
125  result["space_group_range"] = "10-15";
126  } // end monoclinic
127  else {
128  Index tot_ops = 0;
129  for (Index m : op_types) {
130  tot_ops += m;
131  }
132 
133  result["crystal_system"] = "Triclinic";
134 
135  if (op_types[1] == 1 && tot_ops == 2) {
136  result["international_name"] = "-1";
137  result["name"] = "Ci";
138  result["latex_name"] = "C_i";
139  result["space_group_range"] = "2";
140  } else {
141  is_error = true;
142  }
143  }
144 
145  if (is_error || result["crystal_system"].empty()) {
146  throw std::runtime_error(
147  "Error finding centric point group type. Crystal system determined to "
148  "be " +
149  result["crystal_system"]);
150  }
151  return result;
152 }
153 
154 std::map<std::string, std::string> _acentric_point_group_info(
155  std::vector<Index> const &op_types) {
156  std::map<std::string, std::string> result;
157  bool is_error = false;
158  if (op_types[4] == 8) { // 3-fold
159  result["crystal_system"] = "Cubic";
160  if (op_types[6] == 0) { // 4-fold
161  result["international_name"] = "23";
162  result["name"] = "T (Chiral)";
163  result["latex_name"] = "T";
164  result["space_group_range"] = "195-199";
165  } else if (op_types[6] == 6) { // 4-fold
166  result["international_name"] = "432";
167  result["name"] = "O (Chiral)";
168  result["latex_name"] = "O";
169  result["space_group_range"] = "207-214";
170  } else if (op_types[7] == 6) { // improper 4-fold
171  result["international_name"] = "-43m";
172  result["name"] = "Td";
173  result["latex_name"] = "T_d";
174  result["space_group_range"] = "215-220";
175  } else {
176  is_error = true;
177  }
178  } // end cubic;
179  else if (op_types[5] == 2) { // Improper 3-fold
180  result["crystal_system"] = "Hexagonal";
181  if (op_types[2] == 0) { // 2-fold
182  result["international_name"] = "-6";
183  result["name"] = "C3h";
184  result["latex_name"] = "C_{3h}";
185  result["space_group_range"] = "174";
186  } else if (op_types[2] == 3) { // 2-fold
187  result["international_name"] = "-6m2";
188  result["name"] = "D3h";
189  result["latex_name"] = "D_{3h}";
190  result["space_group_range"] = "187-190";
191  }
192 
193  } // end hexagonal 1
194  else if (op_types[10] == 2) { // 6-fold
195  result["crystal_system"] = "Hexagonal";
196  if (op_types[2] == 7) { // 2-fold
197  result["international_name"] = "622";
198  result["name"] = "D6 (Chiral)";
199  result["latex_name"] = "D_{6h}";
200  result["space_group_range"] = "177-182";
201  } else if (op_types[3] == 6) { // mirror
202  result["international_name"] = "6mm";
203  result["name"] = "C6v";
204  result["latex_name"] = "C_{6v}";
205  result["space_group_range"] = "183-186";
206  } else if (op_types[3] == 0) { // mirror
207  result["international_name"] = "6";
208  result["name"] = "C6 (Chiral)";
209  result["latex_name"] = "C_6";
210  result["space_group_range"] = "168-173";
211  } else {
212  is_error = true;
213  }
214  } // end hexagonal 2
215  else if (op_types[4] == 2) { // 3-fold
216  result["crystal_system"] = "Rhombohedral";
217  if (op_types[2] == 3) { // 2-fold
218  result["international_name"] = "32";
219  result["name"] = "D3 (Chiral)";
220  result["latex_name"] = "D_3";
221  result["space_group_range"] = "149-155";
222  } else if (op_types[3] == 3) { // mirror
223  result["international_name"] = "3m";
224  result["name"] = "C3v";
225  result["latex_name"] = "C_{3v}";
226  result["space_group_range"] = "156-161";
227  } else if ((op_types[2] + op_types[3]) == 0) {
228  result["international_name"] = "3";
229  result["name"] = "C3";
230  result["latex_name"] = "C_{3}";
231  result["space_group_range"] = "143-146";
232  } else {
233  is_error = true;
234  }
235  } // end rhombohedral
236  else if (op_types[6] == 2) { // 4-fold
237  result["crystal_system"] = "Tetragonal";
238  if (op_types[2] == 5) { // 2-fold
239  result["international_name"] = "422";
240  result["name"] = "D4 (Chiral)";
241  result["latex_name"] = "D_4";
242  result["space_group_range"] = "89-98";
243  } else if (op_types[3] == 4) { // mirror
244  result["international_name"] = "4mm";
245  result["name"] = "C4v";
246  result["latex_name"] = "C_{4v}";
247  result["space_group_range"] = "99-110";
248  } else if (op_types[2] == 1) { // two-fold
249  result["international_name"] = "4";
250  result["name"] = "C4 (Chiral)";
251  result["latex_name"] = "C_4";
252  result["space_group_range"] = "75-80";
253  } else {
254  is_error = true;
255  }
256  } // end tetragonal 1
257  else if (op_types[7] == 2) { // improper 4-fold
258  result["crystal_system"] = "Tetragonal";
259  if (op_types[2] == 3) { // 2-fold
260  result["international_name"] = "-42m";
261  result["name"] = "D2d";
262  result["latex_name"] = "D_{2d}";
263  result["space_group_range"] = "111-122";
264  } else if (op_types[2] == 1) { // 2-fold
265  result["international_name"] = "-4";
266  result["name"] = "S4";
267  result["latex_name"] = "S_4";
268  result["space_group_range"] = "81-82";
269  } else {
270  is_error = true;
271  }
272  } // end tetragonal 2
273  else if ((op_types[2] + op_types[3]) == 3) { // 2-fold and mirror
274  result["crystal_system"] = "Orthorhomic";
275  if (op_types[2] == 3) { // 2-fold
276  result["international_name"] = "222";
277  result["name"] = "D2 (Chiral)";
278  result["latex_name"] = "D_2";
279  result["space_group_range"] = "16-24";
280  } else if (op_types[3] == 2) { // mirror
281  result["international_name"] = "mm2";
282  result["name"] = "C2v";
283  result["latex_name"] = "C_{2v}";
284  result["space_group_range"] = "25-46";
285  } else {
286  is_error = true;
287  }
288  } // end orthorhombic
289  else if ((op_types[2] + op_types[3]) == 1) { // 2-fold and mirror
290  result["crystal_system"] = "Monoclinic";
291  if (op_types[2] == 1) { // 2-fold
292  result["international_name"] = "2";
293  result["name"] = "C2 (Chiral)";
294  result["latex_name"] = "C_2";
295  result["space_group_range"] = "3-5";
296  } else if (op_types[3] == 1) { // mirror
297  result["international_name"] = "m";
298  result["name"] = "Cs";
299  result["latex_name"] = "C_s";
300  result["space_group_range"] = "6-9";
301  } else {
302  is_error = true;
303  }
304  } // end Acentric monoclinic
305  else {
306  Index tot_ops = 0;
307  for (Index m : op_types) {
308  tot_ops += m;
309  }
310 
311  result["crystal_system"] = "Triclinic";
312 
313  if (tot_ops == 1) {
314  result["international_name"] = "1";
315  result["name"] = "C1 (Chiral)";
316  result["latex_name"] = "C_1";
317  result["space_group_range"] = "1";
318  } else {
319  is_error = true;
320  }
321  }
322 
323  if (is_error || result["crystal_system"].empty()) {
324  throw std::runtime_error(
325  "Error finding acentric point group type. Crystal system determined to "
326  "be " +
327  result["crystal_system"]);
328  }
329 
330  return result;
331 }
332 
333 // Does not work for icosahedral groups
334 static std::map<std::string, std::string> _nonmagnetic_point_group_info(
335  SymGroup const &g) {
336  SymGroup pg = g.copy_no_trans(false);
337  std::vector<Index> op_types = _number_of_operation_types(pg);
338  std::map<std::string, std::string> result;
339  // Calculate total number of rotation elements
340  Index nm = op_types[2] + 1;
341  for (Index k = 4; k < op_types.size(); k++) {
342  nm += op_types[k];
343  }
344  if (op_types[1]) {
345  result = _centric_point_group_info(op_types);
346  result["centricity"] = "Centric";
347  } else {
348  result = _acentric_point_group_info(op_types);
349  result["centricity"] = "Acentric";
350  }
351  return result;
352 }
353 } // namespace Local
354 
355 // INITIALIZE STATIC MEMBER MasterSymGroup::GROUP_COUNT
356 // THIS MUST OCCUR IN A .CC FILE; MAY CAUSE PROBLEMS IF WE
357 // CHANGE COMPILING/LINKING STRATEGY
359 
360 //*******************************************************************************************
361 
363  : SymGroup(RHS),
364  m_group_index(RHS.m_group_index),
365  m_coord_rep_ID(RHS.m_coord_rep_ID),
366  m_reg_rep_ID(RHS.m_reg_rep_ID),
367  m_identity_rep_IDs(RHS.m_identity_rep_IDs) {
368  m_rep_array.reserve(RHS.m_rep_array.size());
369 
370  for (Index i = 0; i < RHS.m_rep_array.size(); i++) {
371  _add_representation(RHS.m_rep_array[i]->copy());
372  }
373 
374  for (Index i = 0; i < size(); i++) at(i).set_index(*this, i);
375 }
376 
377 //*******************************************************************************************
378 
380  clear();
381  return;
382 }
383 
384 //*******************************************************************************************
386  SymGroup::operator=(RHS);
389  m_rep_array.reserve(RHS.m_rep_array.size());
390  for (Index i = 0; i < RHS.m_rep_array.size(); i++)
391  _add_representation(RHS.m_rep_array[i]->copy());
392 
393  for (Index i = 0; i < size(); i++) at(i).set_index(*this, i);
394 
395  return *this;
396 }
397 
398 //*******************************************************************************************
399 
402 
403  back().set_index(*this, size() - 1);
404  return;
405 }
406 
407 //*******************************************************************************************
408 
410  if (!m_point_group.size()) {
411  m_point_group = copy_no_trans(false);
412  }
413  return m_point_group;
414 }
415 
416 //*******************************************************************************************
417 
421  for (Index i = 0; i < m_rep_array.size(); i++) {
422  if (m_rep_array[i]) delete m_rep_array[i];
423  }
424  m_rep_array.clear();
425 
427 
428  m_identity_rep_IDs.clear();
429 
430  // Yes, by the time you return GROUP_COUNT is greater than m_group_index, and
431  // that's how we like it around here.
433 
434  return;
435 }
436 
437 //*******************************************************************************************
438 
441  return m_coord_rep_ID;
442 }
443 
444 //*******************************************************************************************
445 
448  return m_reg_rep_ID;
449 }
450 
451 //*******************************************************************************************
452 
454  if (m_identity_rep_IDs.size() < dim + 1) {
455  auto tail = std::vector<SymGroupRepID>(dim + 1 - m_identity_rep_IDs.size());
456  m_identity_rep_IDs.insert(m_identity_rep_IDs.end(), tail.begin(),
457  tail.end());
458  }
459  if (m_identity_rep_IDs[dim].empty()) {
460  m_rep_array.push_back(new SymGroupRep(*this));
461  for (Index i = 0; i < size(); i++) {
462  m_rep_array.back()->set_rep(i, SymPermutation(Permutation(dim)));
463  }
464  m_identity_rep_IDs[dim] =
465  SymGroupRepID(group_index(), m_rep_array.size() - 1);
466  }
467  return m_identity_rep_IDs[dim];
468 }
469 
470 //*******************************************************************************************
471 
475 }
476 
477 //*******************************************************************************************
478 
480  SymOpRepresentation const &_op_rep,
481  Index op_index) const {
482  _representation_ptr(rep_ID)->set_rep(op_index, _op_rep);
483 }
484 
485 //*******************************************************************************************
486 
490 }
491 
492 //*******************************************************************************************
493 
495  SymGroupRep *coordrep(new SymGroupRep(*this));
496  for (Index i = 0; i < size(); i++)
497  coordrep->set_rep(i, SymMatrixXd(at(i).matrix()));
498 
500  return m_coord_rep_ID;
501 }
502 
503 //*******************************************************************************************
505  SymGroupRep *regrep(new SymGroupRep(*this));
506  Eigen::MatrixXd regrep_mat(size(), size());
507 
508  if (get_alt_multi_table().size() != size()) return SymGroupRepID();
509 
510  for (Index i = 0; i < size(); i++) {
511  for (Index j = 0; j < size(); j++) {
512  for (Index k = 0; k < size(); k++) {
513  if (alt_multi_table[j][k] == i) {
514  regrep_mat(j, k) = 1.0;
515  } else {
516  regrep_mat(j, k) = 0.0;
517  }
518  }
519  }
520  regrep->set_rep(i, SymMatrixXd(regrep_mat));
521  }
522 
524 
525  return m_reg_rep_ID;
526 }
527 
528 //*******************************************************************************************
529 
531  SymGroupRepID ID2) const {
532  SymGroupRep const *rep1(_representation_ptr(ID1)),
533  *rep2(_representation_ptr(ID2));
534  if (!(rep1 && rep2)) return SymGroupRepID();
535 
536  SymGroupRep *new_rep(new SymGroupRep(*this));
537  Eigen::MatrixXd tmat;
538  for (Index i = 0; i < size(); i++) {
539  // std::cout << "rep1 matrix:\n";
540  // std::cout << *(rep1->MatrixXd(i)) << '\n';
541  // std::cout << "rep2 matrix:\n";
542  // std::cout << *(rep2->MatrixXd(i)) << '\n';
543 
544  kroneckerProduct(*(rep1->MatrixXd(i)), *(rep2->MatrixXd(i)), tmat);
545  // std::cout << "Total matrix:\n" << tmat << '\n';
546  new_rep->set_rep(i, SymMatrixXd(tmat));
547  }
548  return _add_representation(new_rep);
549 }
550 
551 //*******************************************************************************************
552 
554  const std::vector<SymGroupRepID> &rep_IDs) const {
555  std::vector<SymGroupRep const *> treps;
556  for (Index i = 0; i < rep_IDs.size(); i++) {
557  treps.push_back(_representation_ptr(rep_IDs[i]));
558  if (!treps.back()) return SymGroupRepID();
559  }
560  SymGroupRep *new_rep(new SymGroupRep(*this));
561 
562  int dim = 0;
563  for (Index i = 0; i < treps.size(); i++) {
564  if (treps[i]->size() != size()) return SymGroupRepID();
565  if (!(treps[i]->MatrixXd(0))) return SymGroupRepID();
566 
567  dim += (treps[i]->MatrixXd(0))->cols();
568  }
569 
570  Eigen::MatrixXd tmat(Eigen::MatrixXd::Zero(dim, dim));
571  int corner = 0;
572  for (Index i = 0; i < size(); i++) {
573  corner = 0;
574  for (Index j = 0; j < treps.size(); j++) {
575  tmat.block(corner, corner, (treps[j]->MatrixXd(i))->cols(),
576  (treps[j]->MatrixXd(i))->cols()) = *(treps[j]->MatrixXd(i));
577  corner += (treps[j]->MatrixXd(i))->cols();
578  }
579  new_rep->set_rep(i, SymMatrixXd(tmat));
580  }
581  return _add_representation(new_rep);
582 }
583 
584 //*******************************************************************************************
585 
587  // make sure coord_rep_ID exists?
588  // Index coord_rep_index((*this).coord_rep_ID());
589  // make a new symmetry representation
590  SymGroupRep *new_rep(new SymGroupRep(*this));
591 
592  // we are going to use our knowledge of how rotation
593  // matrices transform under symmetry (in the coord_rep)
594  // in order to build
595  // up a representation in the rotation basis.
596  for (Index i = 0; i < size(); i++) {
597  // build each 4d representaion for a = 1, b = 1, ...
598  // rp = rotation parameter
599  Eigen::Matrix3d coord_rep_mat = at(i).matrix();
600  if (!almost_equal(coord_rep_mat.determinant(), 1.)) {
601  // std::cout << "IN IF" << std::endl;
602  coord_rep_mat *= coord_rep_mat.determinant();
603  // continue;
604  }
605 
606  Eigen::Quaterniond opq(coord_rep_mat);
607 
608  // std::cout << "Quaternion " << opq << std::endl;
609 
610  // this quaternion can be converted to a 4d rotation as follows
611  // q = q0 q1 q2 q3
612  // Right multiplication : r * q = u
613  //
614  // | q0 -q1 -q2 -q3 | | r0 | | u0 |
615  // | q1 q0 q3 -q2 | | r1 | | u1 |
616  // | q2 -q3 q0 q1 | | r2 | = | u2 |
617  // | q3 q2 -q1 q0 | | q3 | | u3 |
618  //
619  // and Left multiplication : q * r = u
620  //
621  // | q0 -q1 -q2 -q3 | | r0 | | u0 |
622  // | q1 q0 -q3 q2 | | r1 | | u1 |
623  // | q2 q3 q0 -q1 | | r2 | = | u2 |
624  // | q3 -q2 q1 q0 | | q3 | | u3 |
625 
626  // building both for now
627  Eigen::MatrixXd right_q(4, 4);
628  Eigen::MatrixXd left_q(4, 4);
629 
630  right_q(0, 0) = opq.w();
631  right_q(0, 1) = -opq.x();
632  right_q(0, 2) = -opq.y();
633  right_q(0, 3) = -opq.z();
634 
635  right_q(1, 0) = opq.x();
636  right_q(1, 1) = opq.w();
637  right_q(1, 2) = opq.z();
638  right_q(1, 3) = -opq.y();
639 
640  right_q(2, 0) = opq.y();
641  right_q(2, 1) = -opq.z();
642  right_q(2, 2) = opq.w();
643  right_q(2, 3) = opq.x();
644 
645  right_q(3, 0) = opq.z();
646  right_q(3, 1) = opq.y();
647  right_q(3, 2) = -opq.x();
648  right_q(3, 3) = opq.w();
649 
650  left_q(0, 0) = opq.w();
651  left_q(0, 1) = -opq.x();
652  left_q(0, 2) = -opq.y();
653  left_q(0, 3) = -opq.z();
654 
655  left_q(1, 0) = opq.x();
656  left_q(1, 1) = opq.w();
657  left_q(1, 2) = -opq.z();
658  left_q(1, 3) = opq.y();
659 
660  left_q(2, 0) = opq.y();
661  left_q(2, 1) = opq.z();
662  left_q(2, 2) = opq.w();
663  left_q(2, 3) = -opq.x();
664 
665  left_q(3, 0) = opq.z();
666  left_q(3, 1) = -opq.y();
667  left_q(3, 2) = opq.x();
668  left_q(3, 3) = opq.w();
669 
670  // std::cout << right_q << std::endl;
671 
672  new_rep->set_rep(i, SymMatrixXd(left_q));
673  }
674 
675  for (Index i = 0; i < new_rep->size(); i++) {
676  // std::cout << "Rota Rep final mats " << i << std::endl <<
677  // *(new_rep->MatrixXd(i)) << std::endl;
678  }
679 
680  return _add_representation(new_rep);
681 }
682 
683 //*******************************************************************************************
684 
686  SymGroupRepID orig_ID, const Eigen::MatrixXd &trans_mat) const {
687  SymGroupRep const *trep(_representation_ptr(orig_ID));
688  if (!trep) return SymGroupRepID();
689  return add_representation(coord_transformed_copy(*trep, trans_mat));
690 }
691 
692 //*******************************************************************************************
693 
695  SymGroupRepID new_ID(group_index(), m_rep_array.size());
696  m_rep_array.push_back(new SymGroupRep(*this, new_ID));
697  return new_ID;
698 }
699 
700 //*******************************************************************************************
701 
703  const SymGroupRep &new_rep) const {
704  return _add_representation(new_rep.copy());
705 }
706 
707 //*******************************************************************************************
708 
710  SymGroupRepID new_ID(group_index(), m_rep_array.size());
711  m_rep_array.push_back(new_rep);
712  m_rep_array.back()->set_master_group(*this, new_ID);
713  return new_ID;
714 }
715 
716 //*******************************************************************************************
718  return *_representation_ptr(_id);
719 }
720 //*******************************************************************************************
722  if (_id.is_identity()) {
723  // _id.rep_index() stores dimension of representation
724  _id = identity_rep_ID(_id.rep_index());
725  } else if (_id.group_index() != group_index()) {
726  throw std::runtime_error(
727  "Attempting to access representation from MasterGroup #" +
728  std::to_string(group_index()) + " that resides in MasterGroup #" +
729  std::to_string(_id.group_index()));
730  }
731 
732  return m_rep_array[_id.rep_index()];
733 }
734 
735 //*******************************************************************************************
736 
738  SymGroup::sort();
740  bool broken_check(false);
741  std::vector<Index> perm_array(size(), 0);
742  for (Index i = 0; i < size(); i++) {
743  perm_array[i] = at(i).index();
744  if (at(i).index() != i) {
745  at(i).set_index(*this, i);
746  broken_check = true;
747  }
748  }
749  if (broken_check && m_rep_array.size()) {
750  // err_log() << "WARNING: Order of symmetry operations has been altered by
751  // MasterSymGroup::sort_by_class(). Attempting to repair "
752  // << m_rep_array.size() << " symmetry representations.\n";
753  for (Index i = 0; i < m_rep_array.size(); i++) {
754  std::vector<SymOpRepresentation *> new_rep;
755  std::transform(perm_array.begin(), perm_array.end(),
756  std::back_inserter(new_rep),
757  [&](Index &idx) { return (*m_rep_array[i])[idx]; });
758  m_rep_array[i]->swap(new_rep);
759  for (Index j = 0; j < m_rep_array[i]->size(); j++) {
760  if (m_rep_array[i]->at(j)) {
761  (m_rep_array[i]->at(j))
762  ->set_identifiers(*this, m_rep_array[i]->symrep_ID(),
763  j); // perm_array[j]);
764  }
765  }
766  }
767  }
768 
769  return;
770 }
771 
772 //*******************************************************************************************
774  clear();
775  return;
776 }
777 
778 //*******************************************************************************************
780  xtal::SymOpVector lattice_point_group_operations =
783  lattice_point_group_operations, _lat);
784 
785  if (!point_group.is_group(_lat.tol())) {
786  std::cerr << "*** WARNING *** \n"
787  << " SymGroup::lattice_point_group() has been called on an "
788  "ill-conditioned lattice \n"
789  << " (i.e., a well-defined point group could not be found "
790  "with the current tolerance of "
791  << _lat.tol() << ").\n"
792  << " CASM will use the group closure of the symmetry "
793  "operations that were found. Please consider using the \n"
794  << " CASM symmetrization tool on your input files.\n";
795  std::cerr << "lat_column_mat:\n" << _lat.lat_column_mat() << "\n\n";
796 
797  point_group.enforce_group(_lat.tol());
798  }
799  // Sort point_group by trace/conjugacy class
800  point_group.sort();
801 
802  return point_group;
803 }
804 
805 //*******************************************************************************************
806 SymGroup::SymGroup(std::vector<SymOp> from_array, Lattice const *_lat_ptr,
807  PERIODICITY_TYPE init_type)
808  : m_lat_ptr(_lat_ptr), m_group_periodicity(init_type), m_max_error(-1) {
809  std::vector<SymOp>::swap(from_array);
810 }
811 
812 //*******************************************************************************************
813 
814 void SymGroup::set_lattice(const Lattice &lat) { m_lat_ptr = &lat; }
815 
816 /*****************************************************************/
817 
818 void SymGroup::push_back(const SymOp &new_op) {
819  std::vector<SymOp>::push_back(new_op);
820  if (back().map_error() > m_max_error) m_max_error = back().map_error();
821  return;
822 }
823 
824 //*******************************************************************************************
825 
827  multi_table.clear();
828  alt_multi_table.clear();
829  conjugacy_classes.clear();
830  class_names.clear();
831  index2conjugacy_class.clear();
832  irrep_IDs.clear();
833 
834  m_subgroups.clear();
835 
836  centralizer_table.clear();
837  elem_order_table.clear();
838 
839  name.clear();
840  latex_name.clear();
841  comment.clear();
842 
843  return;
844 }
845 
846 //*****************************************************************
847 
850 std::vector<Index> SymGroup::op_indices() const {
851  return master_group_indices();
852 }
853 
854 //*****************************************************************
855 
857 std::vector<Index> SymGroup::master_group_indices() const {
858  std::vector<Index> ind_array(size());
859  for (Index i = 0; i < size(); i++) {
860  if (!valid_index(at(i).index()) && at(i).has_valid_master()) {
861  ind_array[i] = at(i).master_group().find_periodic(at(i));
862  } else {
863  ind_array[i] = at(i).index();
864  }
865  }
866  return ind_array;
867 }
868 
869 //*****************************************************************
870 
872  std::vector<SymOp>::clear();
873 
874  clear_tables();
875 
876  m_max_error = -1;
877 
878  return;
879 }
880 
881 //*****************************************************************
882 std::map<std::string, std::string> point_group_info(SymGroup const &g) {
883  SymGroup pg = g.copy_no_trans(false);
884  SymGroup nonmag;
885  bool grey = false;
886  for (SymOp const &op : pg) {
887  if (!op.time_reversal()) {
888  nonmag.push_back(op);
889  } else if (!grey && op.matrix().isIdentity(TOL)) {
890  grey = true;
891  }
892  }
893  nonmag.set_lattice(g.lattice());
894  auto nonmag_info = Local::_nonmagnetic_point_group_info(nonmag);
895 
896  // nonmagnetic group:
897  if (nonmag.size() == pg.size()) {
898  return nonmag_info;
899  }
900 
901  // grey group:
902  if (grey) { //(2 * nonmag.size()) == pg.size()) {
903  nonmag_info["space_group_range"] = "Magnetic group (not supported)";
904  nonmag_info["international_name"] += "1'";
905  nonmag_info["name"] += "'";
906  nonmag_info["latex_name"].insert(nonmag_info["latex_name"].find('_'), "'");
907  return nonmag_info;
908  }
909 
910  auto tot_info = Local::_nonmagnetic_point_group_info(pg);
911 
912  // magnetic group:
913  tot_info["international_name"] = "Magnetic group (not supported)";
914  tot_info["space_group_range"] = "Magnetic group (not supported)";
915  tot_info["name"] += ("(" + nonmag_info["name"] + ")");
916  tot_info["latex_name"] += ("(" + nonmag_info["latex_name"] + ")");
917 
918  return tot_info;
919 }
920 
921 //*******************************************************************************************
922 /* Loop through SymGroup and populate passed SymGroup
923  * with all the operations but none of the shifts. Unle
924  * explicitly requested, degenerate symmetry operations
925  * will not be added.
926  */
927 //*******************************************************************************************
928 SymGroup SymGroup::copy_no_trans(bool keep_repeated) const {
929  SymGroup result;
930 
931  result.m_lat_ptr = m_lat_ptr;
932  for (Index i = 0; i < size(); i++) {
933  SymOp tsymop(at(i).no_trans());
934  if (keep_repeated || !contains(result, tsymop)) {
935  result.push_back(tsymop);
936  }
937  }
938  return result;
939 }
940 
941 //*******************************************************************************************
942 SymInfo SymGroup::info(Index i) const { return SymInfo(at(i), lattice()); }
943 
944 //*******************************************************************************************
945 
946 double SymGroup::max_error() { return m_max_error; }
947 
948 //*******************************************************************************************
949 
950 const Lattice &SymGroup::lattice() const {
951  assert(m_lat_ptr &&
952  "Attempting to access Lattice of a SymGroup, but it has not been "
953  "initialized!");
954  return *m_lat_ptr;
955 }
956 
957 //*******************************************************************************************
972 void SymGroup::_generate_class_names() const { // AAB
973  if (!conjugacy_classes.size()) {
975  }
976 
977  class_names.resize(conjugacy_classes.size());
978 
979  std::vector<Eigen::Vector3d> highsym_axes;
980  std::vector<int> mult;
981  double angle = 360;
982  double dprod;
983  std::string symtype;
984  Index to_name = conjugacy_classes.size();
985  bool cubic = false;
986 
987  if ((name == "T") || (name == "Td") || (name == "Th") || (name == "O") ||
988  (name == "Oh")) {
989  cubic = true;
990  }
991 
992  class_names[0] = "E";
993  to_name--;
994 
995  std::vector<SymInfo> info;
996  for (Index i = 0; i < size(); i++) info.push_back(SymInfo(at(i), lattice()));
997 
998  // If the SymGroup includes an inversion operation, name it "i"
999  // We can just use back() here because inversion is always last
1000  if (info.back().op_type == symmetry_type::inversion_op) {
1001  class_names[class_names.size() - 1] = "i";
1002  to_name--;
1003  }
1004 
1005  if (to_name == 0) {
1006  return;
1007  }
1008 
1009  // C1h contains only the identity element and sigma h mirror plane, so we deal
1010  // with this specifically...
1011  if (name == "C1h") {
1012  class_names[1] = "h";
1013  to_name--;
1014  }
1015 
1016  if (to_name == 0) {
1017  return;
1018  }
1019 
1020  // This part will loop over all of the proper rotations and look for the axis
1021  // of highest rotational symmetry, which we are going to call the "principal
1022  // axis."
1023  highsym_axes.clear();
1024  mult.clear();
1025 
1026  for (Index i = 0; i < size(); i++) {
1027  if ((info[i].op_type == symmetry_type::rotation_op) ||
1029  if (contains(highsym_axes,
1030  info[i].axis.const_cart())) { // Otherwise, check if the
1031  // axis has been found;
1032  mult[find_index(highsym_axes, info[i].axis.const_cart())]++;
1033  } else {
1034  highsym_axes.push_back(info[i].axis.cart());
1035  mult.push_back(1);
1036  }
1037  }
1038  }
1039 
1040  Eigen::Vector3d hs_axis;
1041  bool hs_axis_set = false;
1042  double hangle = 360;
1043 
1044  for (Index i = 0; i < size(); i++) {
1045  if ((info[i].angle < hangle) && (info[i].angle > TOL)) {
1046  hangle = info[i].angle;
1047  hs_axis = info[i].axis.cart();
1048  hs_axis_set = true;
1049  }
1050  }
1051 
1052  int order = *std::max_element(mult.begin(), mult.end());
1053 
1054  for (int i = (int(mult.size()) - 1); i >= 0; i--) {
1055  if ((cubic == false) && (mult[i] != order)) {
1056  highsym_axes.erase(highsym_axes.begin() + i);
1057  mult.erase(mult.begin() + i);
1058  } else if (mult[i] < (order - 1)) {
1059  highsym_axes.erase(highsym_axes.begin() + i);
1060  mult.erase(mult.begin() + i);
1061  }
1062  }
1063 
1064  // This is kind of a hack... We might want to change this so that the
1065  // principal axis is actually the one with the highest fold rotation, and then
1066  // treat cases like cubic and orthorhombic separately....... but I am not sure
1067  // that's better...
1068 
1069  if (name == "D3d") {
1070  for (int i = int(mult.size()) - 1; i >= 0; i--) {
1071  if (!hs_axis_set) {
1072  throw std::runtime_error(
1073  "Error in _generate_class_names: using hs_axis unitialized");
1074  }
1075  if (!almost_zero(highsym_axes[i] - hs_axis)) {
1076  highsym_axes.erase(highsym_axes.begin() + i);
1077  mult.erase(mult.begin() + i);
1078  }
1079  }
1080  }
1081 
1082  int ind = 0;
1083 
1084  std::string cprime = "'";
1085  std::string sprime = "'";
1086  std::string vprime = "";
1087 
1088  for (Index i = 0; i < size(); i++) { // Loop over all SymOps
1089  // ind = conjugacy_corr_table[i][0];
1090  ind = index2conjugacy_class[i];
1091  std::ostringstream s;
1092  if (!class_names[ind]
1093  .size()) { // Check to see if this has already been named
1094  bool normal = false;
1095  for (Index j = 0; j < highsym_axes.size(); j++) {
1096  dprod = highsym_axes[j].dot(info[i].axis.const_cart());
1097  Eigen::Vector3d xprodvec =
1098  highsym_axes[j].cross(info[i].axis.const_cart());
1099  if (almost_zero(xprodvec.norm())) {
1100  normal = true;
1101  break;
1102  }
1103  }
1104 
1105  if (normal) { // Check if the cross product with principal axis is zero
1106  if ((info[i].angle < 200) &&
1107  (info[i].angle >
1108  1)) { // Only bother with angles that 360 is divisible by
1109  if ((info[i].op_type == symmetry_type::rotation_op) ||
1111  angle = info[i].angle;
1112  symtype = "C";
1113  s << conjugacy_classes[ind].size() << symtype << int(360 / angle);
1114  class_names[ind] = s.str();
1115  to_name--;
1116  // std::cout << " rotation\t==> " << s.str() << std::endl;
1117  } else if (info[i].op_type == symmetry_type::rotoinversion_op) {
1118  angle = info[i].angle;
1119  symtype = "S";
1120  s << conjugacy_classes[ind].size() << symtype << int(360 / angle);
1121  class_names[ind] = s.str();
1122  to_name--;
1123  // std::cout << " rotoinversion\t==> " << s.str() << std::endl;
1124  }
1125  } else if ((info[i].op_type == symmetry_type::mirror_op) ||
1126  (info[i].op_type == symmetry_type::glide_op)) {
1127  symtype = "h";
1128  s << conjugacy_classes[ind].size() << symtype;
1129  class_names[ind] = s.str();
1130  to_name--;
1131  // std::cout << " mirror\t==> " << s.str() << std::endl;
1132  }
1133  } else {
1134  if ((info[i].angle < 200) && (info[i].angle > 1)) {
1135  if ((info[i].op_type == symmetry_type::rotation_op) ||
1136  (info[i].op_type == symmetry_type::screw_op)) {
1137  angle = info[i].angle;
1138  symtype = "C";
1139  s << conjugacy_classes[ind].size() << symtype << int(360 / angle)
1140  << cprime;
1141  class_names[ind] = s.str();
1142  to_name--;
1143  // std::cout << " rotation\t==> " << s.str() << std::endl;
1144  cprime = "''";
1145  } else if (info[i].op_type == symmetry_type::rotoinversion_op) {
1146  angle = info[i].angle;
1147  symtype = "S";
1148  s << conjugacy_classes[ind].size() << symtype << int(360 / angle)
1149  << sprime;
1150  class_names[ind] = s.str();
1151  to_name--;
1152  // std::cout << " rotoinversion\t==> " << s.str() << std::endl;
1153  sprime = "''";
1154  }
1155  } else if ((info[i].op_type == symmetry_type::mirror_op) ||
1156  (info[i].op_type == symmetry_type::glide_op)) {
1157  if (almost_zero(dprod)) {
1158  symtype = "v";
1159  s << conjugacy_classes[ind].size() << symtype << vprime;
1160  class_names[ind] = s.str();
1161  to_name--;
1162  vprime = "'";
1163  } else {
1164  symtype = "d";
1165  s << conjugacy_classes[ind].size() << symtype;
1166  class_names[ind] = s.str();
1167  to_name--;
1168  }
1169  // std::cout << " mirror\t==> " << s.str() << std::endl;
1170  }
1171  }
1172  }
1173  }
1174 
1175  for (Index i = 0; i < class_names.size(); i++) {
1176  std::string one = "1";
1177  if (class_names[i].find(one) != std::string::npos) {
1178  class_names[i].erase(class_names[i].find(one), 1);
1179  }
1180  }
1181 
1182  // This is also a hack... but again, not sure there is a better way...
1183 
1184  if (name == "D2h") {
1185  for (Index i = 0; i < conjugacy_classes.size(); i++) {
1186  if (info[conjugacy_classes[i][0]].op_type == symmetry_type::rotation_op) {
1187  if (almost_zero(info[conjugacy_classes[i][0]].axis.const_cart() -
1188  Eigen::Vector3d::UnitX())) {
1189  class_names[i].append("(x)");
1190  } else if (almost_zero(info[conjugacy_classes[i][0]].axis.const_cart() -
1191  Eigen::Vector3d::UnitY())) {
1192  class_names[i].append("(y)");
1193  } else if (almost_zero(info[conjugacy_classes[i][0]].axis.const_cart() -
1194  Eigen::Vector3d::UnitY())) {
1195  class_names[i].append("(z)");
1196  }
1197  } else if (info[conjugacy_classes[i][0]].op_type ==
1199  if (almost_zero(info[conjugacy_classes[i][0]].axis.const_cart() -
1200  Eigen::Vector3d::UnitX())) {
1201  class_names[i].append("(yz)");
1202  } else if (almost_zero(info[conjugacy_classes[i][0]].axis.const_cart() -
1203  Eigen::Vector3d::UnitY())) {
1204  class_names[i].append("(xz)");
1205  } else if (almost_zero(info[conjugacy_classes[i][0]].axis.const_cart() -
1206  Eigen::Vector3d::UnitZ())) {
1207  class_names[i].append("(xy)");
1208  }
1209  }
1210  }
1211  }
1212 
1213  return;
1214 }
1215 
1216 //*******************************************************************************************
1217 
1228  if (!conjugacy_classes.size()) {
1230  }
1231 
1232  bool all_commute = true;
1233 
1234  centralizer_table.resize(conjugacy_classes.size());
1235 
1236  for (Index i = 0; i < conjugacy_classes.size(); i++) {
1237  all_commute = true;
1238  for (Index j = 0; j < conjugacy_classes[i].size() && all_commute; j++) {
1239  for (Index k = 0; k < multi_table.size(); k++) {
1240  int ind = conjugacy_classes[i][j];
1241  if ((multi_table[ind][k] == multi_table[k][ind]) &&
1242  (!contains(centralizer_table[i], k))) {
1243  centralizer_table[i].push_back(k);
1244  } else {
1245  all_commute = false;
1246  }
1247  }
1248  }
1249  }
1250 }
1251 
1252 //*******************************************************************************************
1254  if (!get_multi_table().size()) {
1255  return;
1256  }
1257 
1258  elem_order_table.resize(size());
1259 
1260  for (Index i = 0; i < size(); i++) {
1261  elem_order_table[i].push_back(i);
1262  }
1263 
1264  Index telem = 0;
1265  Index ind = 0;
1266 
1267  for (Index i = 0; i < size(); i++) {
1268  telem = i;
1269  ind = 0;
1270  do {
1271  telem = multi_table[i][telem];
1272  ind++;
1273  } while (telem != i);
1274  elem_order_table[i].push_back(ind);
1275  }
1276 
1277  return;
1278 }
1279 
1280 //*******************************************************************************************
1281 std::vector<std::set<std::set<Index>>> SymGroup::_small_subgroups() const {
1282  std::vector<std::set<std::set<Index>>> result;
1283 
1284  int tempind = 0;
1285  Index i, j;
1286  if (get_alt_multi_table().size() != size()) {
1287  return result;
1288  }
1289  // identity is a small subgroup
1290  result.push_back({{0}});
1291 
1292  for (i = 1; i < multi_table.size(); i++) {
1293  std::set<Index> tgroup({0, i});
1294  j = i; // ind_prod(i, i);
1295  while (j != 0) {
1296  j = ind_prod(i, j);
1297  tgroup.insert(j);
1298  }
1299 
1300  bool add = true;
1301  for (auto const &orbit : result) {
1302  if (orbit.begin()->size() == tgroup.size() && orbit.count(tgroup) > 0) {
1303  add = false;
1304  break;
1305  }
1306  }
1307  if (!add) continue;
1308 
1309  // use equiv_map to find the equivalent subgroups
1310  result.push_back({});
1311  // std::cout << "tgroup.size(): " << tgroup.size() << std::endl;
1312  // std::cout << "tgroup : ";
1313  // for(i : tgroup)
1314  // std::cout << i << " ";
1315  // std::cout << std::endl;
1316  for (auto const &coset : left_cosets(tgroup.begin(), tgroup.end())) {
1317  std::set<Index> tequiv;
1318  for (Index op : tgroup) {
1319  tempind = ind_prod(op, ind_inverse(coset[0]));
1320  tequiv.insert(ind_prod(coset[0], tempind));
1321  }
1322  result.back().insert(std::move(tequiv));
1323  }
1324  }
1325  return result;
1326 }
1327 
1328 //*******************************************************************************************
1329 /* Start with m_subgroups = m_small_subgroups, then add new subgroups by
1330  * finding the closure of a union of a large_group and a
1331  * small_group. If the the new large_group is unique, add it as a
1332  * large_group. Repeat for all (large_group, small_group) pairs,
1333  * until no new m_subgroups are found. This is probably not the
1334  * fastest algorithm, but it is complete
1335  */
1336 
1338  auto small = _small_subgroups();
1339  m_subgroups = small;
1340  Index i, k, ii, jj, tempind;
1341  for (i = 0; i < m_subgroups.size(); i++) {
1342  // std::cout << "i is " << i << " and m_subgroups.size() is " <<
1343  // m_subgroups.size() << std::endl;
1344  for (auto const &orbit : small) {
1345  for (auto const &equiv : orbit) {
1346  std::set<Index> tgroup = *(m_subgroups[i].begin());
1347  Index init_size = tgroup.size();
1348  tgroup.insert(equiv.begin(), equiv.end());
1349  if (tgroup.size() == init_size) continue;
1350 
1351  // find group closure
1352  std::vector<Index> vgroup(tgroup.begin(), tgroup.end());
1353  for (ii = 0; ii < vgroup.size(); ii++) {
1354  for (jj = 0; jj < vgroup.size(); jj++) {
1355  Index prod = ind_prod(vgroup[ii], vgroup[jj]);
1356  if (tgroup.insert(prod).second) {
1357  vgroup.push_back(prod);
1358  }
1359  }
1360  }
1361 
1362  for (k = 0; k < m_subgroups.size(); k++) {
1363  if (m_subgroups[k].begin()->size() == tgroup.size() &&
1364  m_subgroups[k].count(tgroup) > 0)
1365  break;
1366  }
1367  // std::cout << " k is " << k << " and m_subgroups.size() is " <<
1368  // m_subgroups.size() << std::endl;
1369  if (k < m_subgroups.size()) continue;
1370  // add the new group
1371 
1372  // use equiv_map to find the equivalent subgroups
1373  m_subgroups.push_back({});
1374 
1375  for (auto const &coset : left_cosets(tgroup.begin(), tgroup.end())) {
1376  std::set<Index> tequiv;
1377  for (Index op : tgroup) {
1378  tempind = ind_prod(op, ind_inverse(coset[0]));
1379  tequiv.insert(ind_prod(coset[0], tempind));
1380  }
1381  m_subgroups.back().insert(std::move(tequiv));
1382  }
1383  }
1384  }
1385  }
1386 
1387  // Sort subgroups by number of elements and multiplicity
1388  for (Index i = 0; i < m_subgroups.size(); i++) {
1389  for (Index j = i + 1; j < m_subgroups.size(); j++) {
1390  if (m_subgroups[i].begin()->size() < m_subgroups[j].begin()->size())
1392  else if (m_subgroups[i].begin()->size() ==
1393  m_subgroups[j].begin()->size() &&
1394  m_subgroups[i].size() < m_subgroups[j].size())
1396  }
1397  }
1398  return;
1399 }
1400 
1401 //*******************************************************************************************
1402 
1403 std::vector<SymGroup> SymGroup::unique_subgroups() const {
1404  if (!m_subgroups.size()) _generate_subgroups();
1405 
1406  std::vector<std::string> sg_names, sg_names_limited;
1407  std::vector<bool> chosen_flag(m_subgroups.size(), false);
1408  for (Index i = 0; i < m_subgroups.size(); i++) {
1409  SymGroup sgroup;
1410  sgroup.m_lat_ptr = m_lat_ptr;
1411  for (Index op : *(m_subgroups[i].begin())) {
1412  sgroup.push_back(at(op));
1413  }
1414 
1415  sg_names.push_back(sgroup.get_name());
1416  }
1417 
1418  std::vector<std::vector<Index>> sg_tree(m_subgroups.size(),
1419  std::vector<Index>());
1420  for (Index i = 0; i < m_subgroups.size(); i++) {
1421  // std::cout << "Subgroup " << sg_names[i] << "-" << i << " is also a
1422  // subgroup of ";
1423  for (Index j = 0; j < m_subgroups.size(); j++) {
1424  for (auto const &equiv : m_subgroups[j]) {
1425  bool add = true;
1426  for (auto const &op : equiv) {
1427  if (m_subgroups[i].begin()->count(op) < 1) {
1428  add = false;
1429  break;
1430  }
1431  }
1432  if (add) {
1433  sg_tree[i].push_back(j);
1434  // std::cout << sg_names[j] << "-" << j << "-" << jj << " ";
1435  break;
1436  }
1437  }
1438  }
1439  // std::cout << std::endl;
1440  }
1441 
1442  /* // commented out for now because datatype of m_subgroups has changed
1443  //attempt to maximize coincidence a
1444  int max_co, t_co;
1445  for(int i = int(m_subgroups.size()) - 1; i >= 0; i--) {
1446  if(chosen_flag[i]) continue;
1447  //chosen_flag[i]=true;
1448  for(int j = 0; j < i; j++) {
1449  if(sg_names[j] == sg_names[i]) {
1450  chosen_flag[j] = true;
1451  continue;
1452  }
1453  max_co = 0;
1454  for(Index jj = 0; jj < m_subgroups[j].size(); jj++) {
1455  t_co = m_subgroups[i][0].coincidence(m_subgroups[j][jj]);
1456  if(t_co > max_co) {
1457  max_co = t_co;
1458  m_subgroups[j].swap_elem(jj, 0);
1459  }
1460  }
1461  }
1462  }
1463  */
1464  std::vector<SymGroup> unique_sgroups;
1465 
1466  for (Index i = 0; i < m_subgroups.size(); i++) {
1467  if (chosen_flag[i]) continue;
1468  unique_sgroups.push_back(SymGroup());
1469  for (Index op : *(m_subgroups[i].begin())) {
1470  unique_sgroups.back().push_back(at(op));
1471  }
1472  unique_sgroups.back().sort();
1473  }
1474 
1475  return unique_sgroups;
1476 }
1477 
1478 //*******************************************************************************************
1485 //*******************************************************************************************
1486 
1488  if (get_multi_table().size() != size()) {
1489  return;
1490  }
1491 
1492  conjugacy_classes.clear();
1493 
1494  int k;
1495 
1496  for (Index i = 0; i < size(); i++) {
1497  bool dup_class(false);
1498  for (Index j = 0; j < conjugacy_classes.size(); j++) {
1499  if (contains(conjugacy_classes[j], i)) {
1500  dup_class = true;
1501  break;
1502  }
1503  }
1504  if (dup_class) continue;
1505 
1506  conjugacy_classes.push_back(std::vector<Index>());
1507 
1508  for (Index j = 0; j < size(); j++) {
1509  // std::cout << "for j=" << j << ", i=" << i << ": j-inverse= " <<
1510  // ind_inverse(j) << ", i*j-inverse= " << ind_prod(i, ind_inverse(j)); int
1511  // tk=alt_multi_table[j][i]; std::cout << "-- compare to amt[j][0]=" <<
1512  // alt_multi_table[j][0] << " and amt[j][i]=" << tk << " and result is
1513  // k=";
1514  k = ind_prod(j, ind_prod(i, ind_inverse(j)));
1515  // std::cout << k << " -- compare to explicit value " <<
1516  // multi_table[tk][j];
1517 
1518  if (!contains(conjugacy_classes.back(), k)) {
1519  // std::cout << " so " << k << " goes in class " <<
1520  // conjugacy_classes.size()-1;
1521  conjugacy_classes.back().push_back(k);
1522  }
1523  // std::cout << std::endl;
1524  }
1525  std::sort(conjugacy_classes.back().begin(), conjugacy_classes.back().end());
1526  }
1527 
1528  index2conjugacy_class.resize(size(), 0);
1529  for (Index i = 0; i < conjugacy_classes.size(); i++) {
1530  for (Index j = 0; j < conjugacy_classes[i].size(); j++) {
1532  }
1533  }
1534  // std::cout << "index2conjugacy is " << index2conjugacy_class << '\n';
1535  return;
1536 }
1537 
1538 //*******************************************************************************************
1539 
1541  if (get_alt_multi_table().size() != size() || !valid_index(i) || i >= size())
1542  return -1;
1543  // std::cout << "Inside ind_inverse. 'i' is " << i << " and alt_multi_table
1544  // size is " << alt_multi_table.size() << std::endl;
1545  return alt_multi_table[i][0];
1546 }
1547 
1548 //*******************************************************************************************
1549 
1551  if (get_multi_table().size() != size() || !valid_index(i) || i >= size() ||
1552  !valid_index(j) || j >= size()) {
1553  // err_log() << "WARNING: SymGroup::ind_prod() failed for " << i << ", " <<
1554  // j << std::endl;// and multi_table\n" << get_multi_table() << "\n\n";
1555  // assert(0);
1556  return -1;
1557  }
1558  // std::cout << "Inside ind_prod. 'i' is " << i << " and j is " << j << " and
1559  // multi_table size is " << multi_table.size() << std::endl;
1560  return multi_table[i][j];
1561 }
1562 
1563 //*******************************************************************************************
1564 
1566  if (!get_conjugacy_classes().size() || i > size()) return -1;
1567  return index2conjugacy_class[i];
1568 }
1569 
1570 //*******************************************************************************************
1571 
1573  assert((valid_index(i) && i < irrep_IDs.size()) &&
1574  "Attempting to set ID for out-of-bounds irrep.");
1575  irrep_IDs[i] = ID;
1576  return;
1577 }
1578 
1579 //*******************************************************************************************
1580 
1582  if (!valid_index(i) || i >= irrep_IDs.size()) return SymGroupRepID();
1583 
1584  return irrep_IDs[i];
1585 }
1586 
1587 //*******************************************************************************************
1588 
1590  if (!size() || !at(0).has_valid_master()) {
1591  err_log() << "CRITICAL ERROR: In SymGroup::get_coord_rep_ID(), SymGroup is "
1592  "improperly initialized.\n"
1593  << " Exiting...\n";
1594  exit(1);
1595  }
1596 
1597  return at(0).master_group().coord_rep_ID();
1598 }
1599 //*******************************************************************************************
1600 
1602  if (!size() || !at(0).has_valid_master()) {
1603  err_log() << "CRITICAL ERROR: In SymGroup::allocate_representation(), "
1604  "SymGroup is improperly initialized.\n"
1605  << " Exiting...\n";
1606  exit(1);
1607  }
1608 
1609  return at(0).master_group().allocate_representation();
1610 }
1611 
1612 //*******************************************************************************************
1613 
1615  if (!size() || !valid_index(i) || i >= irrep_IDs.size())
1616  throw std::runtime_error(std::string("Cannot find irrep ") +
1617  std::to_string(i) + " in the current SymGroup\n");
1618 
1619  return at(0).master_group().representation(irrep_IDs[i]);
1620 }
1621 
1622 //*******************************************************************************************
1623 // The set of left cosets is identical to the equivalence_map formed by
1624 // partitioning (*this) w.r.t. 'subgroup'
1625 std::vector<std::vector<Index>> SymGroup::left_cosets(
1626  const std::vector<SymOp> &subgroup, double tol) const {
1627  std::vector<Index> sg_inds = find_all_periodic(subgroup, tol);
1628  return left_cosets(sg_inds.begin(), sg_inds.end());
1629 }
1630 
1631 //*******************************************************************************************
1632 
1633 const std::vector<std::vector<Index>> &SymGroup::get_multi_table() const {
1634  if (multi_table.size() != size()) {
1635  // std::cout << "CALCULATING MULTI_TABLE for " << this << ": table size is
1636  // " << multi_table.size() << " and group size is " << size() << "!!\n";
1638  }
1639  return multi_table;
1640 }
1641 
1642 //*******************************************************************************************
1643 
1644 const std::vector<std::vector<Index>> &SymGroup::get_alt_multi_table() const {
1645  if (alt_multi_table.size() != size()) {
1646  // std::cout << "CALCULATING ALT_MULTI_TABLE " << this << ": table size is "
1647  // << alt_multi_table.size() << " and group size is " << size() << "!!\n";
1649  }
1650  return alt_multi_table;
1651 }
1652 //*******************************************************************************************
1653 
1655  multi_table.resize(size(), std::vector<Index>(size(), -1));
1656  alt_multi_table.resize(size(), std::vector<Index>(size(), -1));
1657 }
1658 
1659 //*******************************************************************************************
1660 
1661 const std::vector<std::vector<Index>> &SymGroup::get_conjugacy_classes() const {
1662  if (conjugacy_classes.size() != size()) _generate_conjugacy_classes();
1663  return conjugacy_classes;
1664 }
1665 
1666 //*******************************************************************************************
1667 
1668 const std::string &SymGroup::get_name() const {
1669  if (!name.size()) {
1670  auto info = point_group_info(*this);
1671  name = info["name"];
1672  latex_name = info["latex_name"];
1673  if (!name.size()) {
1674  err_log()
1675  << "WARNING: In SymGroup::get_name(), unable to get symgroup type.\n";
1676  err_log() << "group size is " << size() << '\n';
1677  name = "unknown";
1678  latex_name = "unknown";
1679  }
1680  }
1681 
1682  return name;
1683 }
1684 
1685 //*******************************************************************************************
1686 
1687 const std::string &SymGroup::get_latex_name() const {
1688  get_name();
1689 
1690  return latex_name;
1691 }
1692 
1693 //*******************************************************************************************
1694 
1695 const std::vector<std::set<std::set<Index>>> &SymGroup::subgroups() const {
1696  if (!m_subgroups.size()) _generate_subgroups();
1697  return m_subgroups;
1698 }
1699 
1700 //*******************************************************************************************
1701 
1702 bool SymGroup::_generate_multi_table() const { // AAB
1703  Index i, j;
1704  multi_table.resize(size(), std::vector<Index>(size(), -1));
1705 
1706  for (i = 0; i < size(); i++) {
1707  for (j = 0; j < size(); j++) {
1708  multi_table[i][j] = find_periodic(at(i) * at(j));
1709  if (multi_table[i][j] >= size() ||
1710  find_index(multi_table[i], multi_table[i][j]) != j) {
1711  // this is a hack (sort of). If find_periodic doesn't work, we try
1712  // find_no trans, which *should* work. In other words, we are using
1713  // 'inuition' to determine that user doesn't really care about the
1714  // translational aspects. If our intuition is wrong, there will will
1715  // probably be an obvious failure later.
1716  multi_table[i][j] = find_no_trans(at(i) * at(j));
1717  if (multi_table[i][j] >= size() ||
1718  find_index(multi_table[i], multi_table[i][j]) != j) {
1719  // if(multi_table[i][j] >= size()) {
1720  // std::cout << "This SymGroup is not a group because the combination
1721  // of at least two of its elements is not contained in the set.\n";
1722 
1723  // ing a table of all 1's seems to make the most sense. This will
1724  // prevent weird recursion from happening.
1725  err_log() << "Failed to construc multiplication table! Table in "
1726  "progress:\n";
1727  for (Index m = 0; m < multi_table.size(); m++) {
1728  for (Index n = 0; n < multi_table[m].size(); n++) {
1729  err_log() << multi_table[m][n] << " ";
1730  }
1731  err_log() << std::endl;
1732  }
1733  err_log() << std::endl;
1734  multi_table.resize(size(), std::vector<Index>(size(), -1));
1735  // multi_table.clear();
1736  return false;
1737  }
1738  }
1739  }
1740  }
1741 
1742  return true;
1743 }
1744 
1745 //*******************************************************************************************
1747  // by calling get_multi_table(), we ensure that multi_table is populated
1748  alt_multi_table.resize(get_multi_table().size());
1749 
1750  if (multi_table.size() && !valid_index(multi_table[0][0])) {
1751  alt_multi_table.resize(size(), std::vector<Index>(size(), -1));
1752  return;
1753  }
1754  for (Index i = 0; i < multi_table.size(); i++) {
1755  if (multi_table[i][i] != 0) {
1757  } else {
1758  alt_multi_table[i] = multi_table[i];
1759  }
1760  }
1761 }
1762 
1763 //*******************************************************************************************
1764 // Please keep in mind that this will only return the FIRST match that is found.
1765 // This does not guarantee that it is the only match.
1766 
1767 Index SymGroup::find_no_trans(const SymOp &test_op) const {
1768  for (Index i = 0; i < size(); i++) {
1769  if (almost_equal(at(i).matrix(), test_op.matrix())) {
1770  return i;
1771  }
1772  }
1773 
1774  return size();
1775 }
1776 
1777 //*******************************************************************************************
1778 
1779 Index SymGroup::find_periodic(const SymOp &test_op, double tol) const {
1780  for (Index i = 0; i < size(); i++) {
1781  if (compare_periodic(at(i), test_op, lattice(), periodicity(), tol)) {
1782  return i;
1783  }
1784  }
1785  return size();
1786 }
1787 
1788 //*******************************************************************************************
1789 
1790 std::vector<Index> SymGroup::find_all_periodic(
1791  const std::vector<SymOp> &subgroup, double tol) const {
1792  std::vector<Index> tarray;
1793  for (Index i = 0; i < subgroup.size(); i++) {
1794  tarray.push_back(find_periodic(subgroup[i], tol));
1795  if (tarray.back() == size()) {
1796  tarray.clear();
1797  break;
1798  }
1799  }
1800  return tarray;
1801 }
1802 
1803 //*******************************************************************************************
1804 // Probably need to change this...
1805 bool SymGroup::is_group(double tol) const {
1806  // This is important because it ensures that things like
1807  // within() and min_dist() work correctly for your group
1808  // regardless of what kind of group it is.
1809 
1810  for (Index i = 0; i < size(); i++) {
1811  for (Index j = 0; j < size(); j++) {
1812  if (!contains_periodic(at(i) * at(j), tol)) return false;
1813  }
1814  if (!contains_periodic(at(i).inverse(), tol)) return false;
1815  }
1816  return true;
1817 }
1818 
1819 //*******************************************************************************************
1820 
1821 void SymGroup::enforce_group(double tol, Index max_size) {
1822  bool new_ops(true);
1823 
1824  while (new_ops && size() < max_size) {
1825  new_ops = false;
1826  for (Index i = 0; i < size() && size() < max_size; i++) {
1827  SymOp A_op(at(i).unregistered_copy());
1828  for (Index j = 0; j < size() && size() < max_size; j++) {
1829  SymOp B_op(at(j).unregistered_copy());
1830 
1831  SymOp tOp(A_op * B_op);
1832 
1833  if (!contains_periodic(tOp, tol)) {
1835  new_ops = true;
1836  // //std::cout << "Pushing back a SymOp due to multiplication
1837  // fail.\n";
1838  }
1839  }
1840 
1841  SymOp tOp(A_op.inverse());
1842  if (!contains_periodic(tOp, tol)) {
1844  new_ops = true;
1845  // std::cout << "Pushing back a SymOp due to inverse fail.\n";
1846  }
1847  }
1848  }
1849  if (size() >= max_size - 1) {
1850  err_log() << "In SymGroup::enforce_group() -- you have reached the maximum "
1851  "allowed size you specified for your group (the default is "
1852  "200). Unless you are generating a factor group in a large "
1853  "supercell, you probably need to adjust your tolerances.\n";
1854  assert(0);
1855  }
1856  return;
1857 }
1858 
1859 //*******************************************************************************************
1860 
1861 bool SymGroup::contains_periodic(const SymOp &test_op, double tol) const {
1862  return find_periodic(test_op, tol) != size();
1863 }
1864 
1865 //*******************************************************************************************
1866 
1868  for (Index i = 0; i < size(); i++) at(i).apply_sym(op);
1869  return *this;
1870 }
1871 
1872 //*******************************************************************************************
1873 
1874 void SymGroup::print(std::ostream &out, COORD_TYPE mode) const {
1875  out << size() << " # " << xtal::COORD_MODE::NAME(mode)
1876  << " representation of group containing " << size() << " elements:\n\n";
1878  if (mode == FRAC) c2f_mat = lattice().inv_lat_column_mat();
1879  for (Index i = 0; i < size(); i++) {
1880  out << i + 1 << " " << description(at(i), lattice(), mode) << std::endl;
1881  at(i).print(out, c2f_mat);
1882  out << std::endl;
1883  }
1884  return;
1885 }
1886 
1887 //*******************************************************************************************
1888 
1890  const Lattice &_cell) const {
1891  if (!size()) return;
1892 
1893  Eigen::Vector3i max_trans(3, 3, 3);
1894  xtal::Coordinate trans(Eigen::Vector3d::Zero(), _cell, FRAC);
1895  space_group_cell.clear();
1896 
1897  std::vector<SymInfo> sg_info;
1898  for (Index i = 0; i < size(); i++) {
1899  EigenCounter<Eigen::Vector3i> lat_comb(-max_trans, max_trans,
1900  Eigen::Vector3i::Ones());
1901  do {
1902  trans.frac() = lat_comb().cast<double>();
1903  SymOp new_sym(SymOp::translation(trans.cart()) * at(i));
1904  SymInfo info(new_sym, lattice());
1905  trans = info.location;
1906  if (!trans.is_within()) {
1907  continue;
1908  }
1909 
1910  bool new_location = true;
1911  for (Index j = 0; j < space_group_cell.size(); j++) {
1912  if (almost_equal(new_sym.matrix(), space_group_cell[j].matrix()) &&
1914  sg_info[j].location.const_cart())) {
1915  new_location = false;
1916  break;
1917  }
1918  }
1919  if (new_location) {
1920  space_group_cell.push_back(new_sym);
1921  sg_info.push_back(info);
1922  }
1923  } while (++lat_comb);
1924  }
1925 
1926  return;
1927 }
1928 
1929 //*******************************************************************************************
1930 
1932  const Lattice &_cell,
1933  Eigen::Vector3i min_trans,
1934  Eigen::Vector3i max_trans) const {
1935  if (!size()) return;
1936 
1937  xtal::Coordinate trans(Eigen::Vector3d::Zero(), _cell, FRAC);
1938 
1939  for (Index i = 0; i < size(); i++) {
1940  EigenCounter<Eigen::Vector3i> lat_comb(min_trans, max_trans,
1941  Eigen::Vector3i::Ones());
1942  do {
1943  trans.frac() = lat_comb().cast<double>();
1944 
1945  SymOp new_sym(SymOp::translation(trans.cart()) * at(i));
1946 
1947  if (!contains(space_group, new_sym)) {
1948  space_group.push_back(new_sym);
1949  }
1950 
1951  } while (++lat_comb);
1952  }
1953 
1954  return;
1955 }
1956 
1957 //***************************************************
1958 void SymGroup::print_locations(std::ostream &stream) const {
1959  // Assumes SymGroup is sorted with clumps of SymOps of common matrix type and
1960  // eigenvec sort();
1961 
1962  bool new_op = true;
1963  stream << "Locations for symmetry operations\n";
1964  SymInfo info(at(0), lattice());
1965  SymInfo next_info(info);
1967  for (Index i = 0; i < size(); i++) {
1968  if (new_op) {
1969  at(i).print(stream, c2f_mat);
1970 
1971  stream << std::endl;
1972  at(i).print(stream, Eigen::Matrix3d::Identity());
1973  stream << std::endl;
1974 
1975  stream << "Location:" << std::endl;
1976  stream << "FRAC\t\t\t\t\tCART" << std::endl;
1977  }
1978  stream << info.location.const_frac();
1979  stream << "\t\t\t";
1980  stream << info.location.const_cart();
1981  stream << std::endl;
1982 
1983  if (i + 1 < size()) {
1984  next_info = SymInfo(at(i + 1), lattice());
1985  if (info.op_type == next_info.op_type &&
1986  almost_equal(info.axis.const_cart(), next_info.axis.const_cart())) {
1987  // Is this enough to know if it's a new symmetry or not?
1988  new_op = false;
1989  } else {
1990  new_op = true;
1991  stream << "------------------------------------------------------------"
1992  "----------------------\n\n";
1993  }
1994  }
1995  info = next_info;
1996  }
1997  return;
1998 }
1999 
2000 //*******************************************************************************************
2001 
2017  // floating point comparison tolerance
2018  double tol = TOL;
2019 
2020  // COORD_TYPE print_mode = CART;
2021 
2022  // compare on vector of '-det', '-trace', 'angle', 'axis', 'tau'
2023  typedef Eigen::Matrix<double, 10, 1> key_type;
2024  auto make_key = [](const SymOp &op, const Lattice &lat) {
2025  key_type vec;
2026  int offset = 0;
2027 
2028  SymInfo info(op, lat);
2029  vec[offset] = double(op.time_reversal());
2030  offset++;
2031 
2032  vec[offset] = -op.matrix().determinant();
2033  offset++;
2034 
2035  vec[offset] = -op.matrix().trace();
2036  offset++;
2037 
2038  vec[offset] = info.angle;
2039  offset++;
2040 
2041  vec.segment<3>(offset) = info.axis.const_frac();
2042  offset += 3;
2043 
2044  vec.segment<3>(offset) = xtal::Coordinate(op.tau(), lat, CART).const_frac();
2045  offset += 3;
2046 
2047  return vec;
2048  };
2049 
2050  // define symop compare function
2051  auto op_compare = [tol](const key_type &A, const key_type &B) {
2052  return float_lexicographical_compare(A, B, tol);
2053  };
2054 
2055  typedef std::map<key_type, SymOp,
2056  std::reference_wrapper<decltype(op_compare)>>
2057  map_type;
2058 
2059  // sort conjugacy class using the first symop in the sorted class
2060  auto cclass_compare = [tol](const map_type &A, const map_type &B) {
2061  return float_lexicographical_compare(A.begin()->first, B.begin()->first,
2062  tol);
2063  };
2064 
2065  // sort elements in each conjugracy class (or just put all elements in the
2066  // first map)
2067  std::set<map_type, std::reference_wrapper<decltype(cclass_compare)>> sorter(
2068  cclass_compare);
2069 
2070  // first put identity in position 0 in order to calculat multi_table correctly
2071  for (int i = 0; i < size(); ++i) {
2072  if (at(i).is_identity()) {
2073  std::swap(at(0), at(i));
2074  break;
2075  }
2076  }
2077 
2078  // if sorting by congujacy classes
2079  if (get_multi_table().size() == size()) {
2080  // get conjugacy classes
2081  get_conjugacy_classes().size();
2082 
2083  // insert elements into each conjugacy class to sort the class
2084  for (int i = 0; i < conjugacy_classes.size(); ++i) {
2085  map_type cclass(op_compare);
2086  for (int j = 0; j < conjugacy_classes[i].size(); ++j) {
2087  const SymOp &op = at(conjugacy_classes[i][j]);
2088  cclass.insert(std::make_pair(make_key(op, lattice()), op));
2089  }
2090 
2091  sorter.emplace(std::move(cclass));
2092  }
2093  } else {
2094  // else just sort element
2095  map_type all_op(op_compare);
2096  for (auto it = begin(); it != end(); ++it) {
2097  all_op.emplace(make_key(*it, lattice()), *it);
2098  }
2099  sorter.emplace(std::move(all_op));
2100  }
2101 
2102  // copy symop back into group
2103  int j = 0;
2104  for (auto const &cclass : sorter) {
2105  for (auto it = cclass.begin(); it != cclass.end(); ++it) {
2106  at(j) = it->second;
2107  ++j;
2108  }
2109  }
2110 
2111  clear_tables();
2112 }
2113 
2114 //*******************************************************************************************
2115 
2117  double tvalue = 0;
2118 
2119  for (Index i = 0; i < size(); i++) {
2120  tvalue += (at(i).matrix().trace()) * (at(i).matrix().trace());
2121  }
2122 
2123  if (Index(std::abs(tvalue)) == size()) {
2124  return true;
2125  } else {
2126  return false;
2127  }
2128 }
2129 
2130 //*******************************************************************************************
2133  const Eigen::Ref<const SymOp::vector_type> &shift) {
2134  for (Index ng = 0; ng < size(); ng++) at(ng) += shift;
2135  return (*this);
2136 }
2137 
2138 //*******************************************************************************************
2139 
2141  const Eigen::Ref<const SymOp::vector_type> &shift) {
2142  for (Index ng = 0; ng < size(); ng++) at(ng) -= shift;
2143  return (*this);
2144 }
2145 
2146 //*******************************************************************************************
2147 
2149  Lattice const &_lattice) {
2150  MasterSymGroup result;
2151  result.set_lattice(_lattice);
2152  for (auto const &op : _group) {
2153  result.push_back(op);
2154  }
2155  return result;
2156 }
2157 
2158 //**********************************************************
2159 
2160 bool compare_periodic(const SymOp &a, const SymOp &b, const Lattice &lat,
2161  PERIODICITY_TYPE periodicity, double _tol) {
2162  if (a.time_reversal() != b.time_reversal() ||
2163  !almost_equal(a.matrix(), b.matrix(), _tol))
2164  return false;
2165  // std::cout << "Operations:\n"
2166  //<< a.matrix() << "\n and \n"
2167  //<< b.matrix() << "\n are equal \n"
2168  //<< "a-tau " << a.tau().transpose() << std::endl
2169  //<< "b-tau " << b.tau().transpose() << std::endl;
2170  if (periodicity != PERIODIC) return almost_equal(a.tau(), b.tau(), _tol);
2171 
2172  return xtal::Coordinate(a.tau(), lat, CART)
2173  .min_dist(xtal::Coordinate(b.tau(), lat, CART)) < _tol;
2174 }
2175 
2176 //**********************************************************
2177 
2178 SymOp within_cell(const SymOp &a, const Lattice &lat,
2179  PERIODICITY_TYPE periodicity) {
2180  if (periodicity != PERIODIC) return a;
2181 
2182  xtal::Coordinate trans(a.tau(), lat, CART);
2183  trans.within();
2184  return SymOp(a.matrix(), trans.cart(), a.time_reversal(), a.map_error());
2185 }
2186 
2187 } // namespace CASM
std::set< std::string > & s
Index count
A Counter allows looping over many incrementing variables in one loop.
Definition: Counter.hh:109
SymGroup m_point_group
Copy of *this with translations removed.
Definition: SymGroup.hh:385
SymGroupRepID allocate_representation() const
Add a new empty representation.
Definition: SymGroup.cc:694
SymGroupRepID add_kronecker_rep(SymGroupRepID ID1, SymGroupRepID ID2) const
Definition: SymGroup.cc:530
static Index GROUP_COUNT
Definition: SymGroup.hh:363
SymGroupRep * _representation_ptr(SymGroupRepID _id) const
Definition: SymGroup.cc:721
void sort()
Sort SymOp in the SymGroup.
Definition: SymGroup.cc:737
void set_rep(SymGroupRepID _rep_ID, SymOpRepresentation const &_op_rep, Index op_index) const
Definition: SymGroup.cc:479
SymGroupRepID reg_rep_ID() const
Definition: SymGroup.cc:446
SymGroupRepID _add_representation(SymGroupRep *_rep_ptr) const
Definition: SymGroup.cc:709
const SymGroup & point_group() const
Definition: SymGroup.cc:409
void push_back(const SymOp &op)
Definition: SymGroup.cc:400
MasterSymGroup(PERIODICITY_TYPE init_type=PERIODIC)
Definition: SymGroup.hh:294
MasterSymGroup & operator=(const MasterSymGroup &RHS)
Definition: SymGroup.cc:385
SymGroupRep const & representation(SymGroupRepID i) const
Const access of alternate Representations of a SymGroup.
Definition: SymGroup.cc:717
SymGroupRepID identity_rep_ID(Index dim) const
Definition: SymGroup.cc:453
std::vector< SymGroupRepID > m_identity_rep_IDs
Definition: SymGroup.hh:382
SymGroupRepID coord_rep_ID() const
Definition: SymGroup.cc:439
SymGroupRepID add_representation(const SymGroupRep &new_rep) const
Definition: SymGroup.cc:702
SymGroupRepID add_rotation_rep() const
Definition: SymGroup.cc:586
std::vector< SymGroupRep * > m_rep_array
Definition: SymGroup.hh:371
SymGroupRep const & coord_rep() const
Definition: SymGroup.cc:472
SymGroupRepID add_direct_sum_rep(const std::vector< SymGroupRepID > &rep_IDs) const
Definition: SymGroup.cc:553
SymGroupRepID m_coord_rep_ID
ID of Cartesian representation.
Definition: SymGroup.hh:374
SymGroupRepID m_reg_rep_ID
Definition: SymGroup.hh:378
SymGroupRepID add_transformed_rep(SymGroupRepID orig_ID, const Eigen::MatrixXd &trans_mat) const
Definition: SymGroup.cc:685
SymGroupRepID _add_coord_rep() const
Definition: SymGroup.cc:494
Index group_index() const
Definition: SymGroup.hh:300
SymGroupRep const & reg_rep() const
Definition: SymGroup.cc:487
SymGroupRepID _add_reg_rep() const
Definition: SymGroup.cc:504
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
Definition: SymGroup.hh:42
Lattice const * m_lat_ptr
Pointer to a lattice for doing periodic comparisons.
Definition: SymGroup.hh:226
virtual void clear()
Definition: SymGroup.cc:871
std::vector< SymGroup > unique_subgroups() const
Definition: SymGroup.cc:1403
bool is_irreducible() const
Definition: SymGroup.cc:2116
const std::string & get_latex_name() const
Definition: SymGroup.cc:1687
std::vector< Index > op_indices() const
Definition: SymGroup.cc:850
SymGroup & apply_sym(const SymOp &op)
Calls 'apply_sym' on all SymOps in the group.
Definition: SymGroup.cc:1867
std::vector< std::set< std::set< Index > > > _small_subgroups() const
Definition: SymGroup.cc:1281
const std::vector< std::set< std::set< Index > > > & subgroups() const
Definition: SymGroup.cc:1695
PERIODICITY_TYPE periodicity() const
Definition: SymGroup.hh:191
double max_error()
This returns the group's max_error.
Definition: SymGroup.cc:946
SymGroup & operator-=(const Eigen::Ref< const SymOp::vector_type > &shift)
Definition: SymGroup.cc:2140
SymGroupRepID coord_rep_ID() const
Definition: SymGroup.cc:1589
const std::string & get_name() const
Definition: SymGroup.cc:1668
virtual void clear_tables()
Definition: SymGroup.cc:826
void _generate_subgroups() const
Definition: SymGroup.cc:1337
bool contains_periodic(const SymOp &test_op, double tol=TOL) const
Check to see if a SymOp is contained in in SymGroup.
Definition: SymGroup.cc:1861
multivector< Index >::X< 2 > alt_multi_table
Definition: SymGroup.hh:236
Index ind_inverse(Index i) const
Get index of operation that is inverse of operation at(i)
Definition: SymGroup.cc:1540
void print(std::ostream &out, COORD_TYPE mode) const
Print the SymGroup to a stream.
Definition: SymGroup.cc:1874
std::vector< std::vector< Index > > conjugacy_classes
Definition: SymGroup.hh:240
std::vector< SymGroupRepID > irrep_IDs
Definition: SymGroup.hh:245
bool _generate_multi_table() const
Definition: SymGroup.cc:1702
double m_max_error
Definition: SymGroup.hh:258
void _generate_elem_order_table() const
Definition: SymGroup.cc:1253
SymGroup(PERIODICITY_TYPE init_type=PERIODIC)
Initialize by setting periodicity mode (default mode is PERIODIC)
Definition: SymGroup.hh:50
multivector< Index >::X< 2 > elem_order_table
Definition: SymGroup.hh:252
const std::vector< std::vector< Index > > & get_alt_multi_table() const
Definition: SymGroup.cc:1644
const std::vector< std::vector< Index > > & get_multi_table() const
Definition: SymGroup.cc:1633
virtual void sort()
Sort SymOp in the SymGroup.
Definition: SymGroup.cc:2016
bool is_group(double tol=TOL) const
Check to see if SymGroup satisfies the group property.
Definition: SymGroup.cc:1805
Index ind_prod(Index i, Index j) const
Get index of operation that is result of multiplication of at(i)*at(j)
Definition: SymGroup.cc:1550
std::vector< std::string > class_names
Definition: SymGroup.hh:241
std::vector< Index > master_group_indices() const
Return the MasterSymGroup indices of the operations in this SymGroup.
Definition: SymGroup.cc:857
virtual void push_back(const SymOp &new_op)
Definition: SymGroup.cc:818
Index class_of_op(Index i) const
Get conjugacy class index of operation at(i)
Definition: SymGroup.cc:1565
void calc_space_group_in_range(SymGroup &space_group, const Lattice &_cell, Eigen::Vector3i min_trans, Eigen::Vector3i max_trans) const
Definition: SymGroup.cc:1931
SymGroup copy_no_trans(bool keep_repeated=false) const
Fill up a SymGroup with *this minus the shifts.
Definition: SymGroup.cc:928
void _generate_class_names() const
Definition: SymGroup.cc:972
Index find_periodic(const SymOp &test_op, double tol=TOL) const
Definition: SymGroup.cc:1779
const std::vector< std::vector< Index > > & get_conjugacy_classes() const
Definition: SymGroup.cc:1661
void set_lattice(const Lattice &new_lat)
Lattice used for periodic comparisons (for instance, to generate multiplcation table)
Definition: SymGroup.cc:814
std::vector< Index > find_all_periodic(const std::vector< SymOp > &subgroup, double tol=TOL) const
Definition: SymGroup.cc:1790
void enforce_group(double tol=TOL, Index max_size=200)
Enforce group property by adding products of operations to the group.
Definition: SymGroup.cc:1821
void _generate_centralizers() const
Definition: SymGroup.cc:1227
SymInfo info(Index i) const
Definition: SymGroup.cc:942
void set_irrep_ID(Index i, SymGroupRepID ID) const
set symrep ID of a particular irrep
Definition: SymGroup.cc:1572
void calc_space_group_in_cell(SymGroup &space_group, const Lattice &_cell) const
Definition: SymGroup.cc:1889
std::string latex_name
Definition: SymGroup.hh:255
void print_locations(std::ostream &stream) const
print locations of the symmetry-generating element of each SymOp
Definition: SymGroup.cc:1958
void _generate_alt_multi_table() const
Definition: SymGroup.cc:1746
SymGroupRepID allocate_representation() const
Add a new empty representation.
Definition: SymGroup.cc:1601
Index find_no_trans(const SymOp &test_op) const
Check to see if a SymOp is contained in in SymGroup and return its index.
Definition: SymGroup.cc:1767
const Lattice & lattice() const
Lattice used for periodic comparisons (for instance, to generate multiplcation table)
Definition: SymGroup.cc:950
std::vector< std::vector< Index > > left_cosets(const std::vector< SymOp > &subgroup, double tol=TOL) const
Definition: SymGroup.cc:1625
multivector< Index >::X< 2 > multi_table
multi_table[i][j] gives index of operation that is result of at(i)*at(j)
Definition: SymGroup.hh:232
multivector< Index >::X< 2 > centralizer_table
Definition: SymGroup.hh:251
std::vector< Index > index2conjugacy_class
Definition: SymGroup.hh:242
static SymGroup lattice_point_group(Lattice const &_lat)
Definition: SymGroup.cc:779
SymGroupRepID get_irrep_ID(Index i) const
Get symrep ID of a particular irrep.
Definition: SymGroup.cc:1581
std::vector< std::set< std::set< Index > > > m_subgroups
Definition: SymGroup.hh:249
SymGroup & operator+=(const Eigen::Ref< const SymOp::vector_type > &shift)
Cartesian translation of SymGroup origin by vector 'shift'.
Definition: SymGroup.cc:2132
std::string comment
Definition: SymGroup.hh:256
void invalidate_multi_tables() const
Definition: SymGroup.cc:1654
virtual ~SymGroup()
Definition: SymGroup.cc:773
void _generate_conjugacy_classes() const
Definition: SymGroup.cc:1487
SymGroupRep const & get_irrep(Index i) const
Get symrep for a particular irrep.
Definition: SymGroup.cc:1614
std::string name
Definition: SymGroup.hh:254
SymGroupRep is an alternative representation of a SymGroup for something other than real space....
Definition: SymGroupRep.hh:31
SymGroupRep * copy() const
Returns pointer to unmanaged copy of this SymGroupRep.
Definition: SymGroupRep.hh:125
void set_rep(Index op_index, const SymOpRepresentation &new_rep)
Sets the representation of operation at entry 'op_index' of this group representation Throws if this ...
Definition: SymGroupRep.cc:114
Eigen::MatrixXd const * MatrixXd(Index i) const
pointer to MatrixXd corresponding to SymOpRepresentation at entry 'i' of this SymGroupRep Returns nul...
Definition: SymGroupRep.cc:144
Type-safe ID object for communicating and accessing Symmetry representation info.
Index rep_index() const
Index of SymGroupRep within the master group Used internally to MasterSymGroup to access the correct ...
Index group_index() const
Index of master group in which the corresponding SymGroupRep is stored Used internally to MasterSymGr...
bool empty() const
Returns true if SymGroupRepID has not been initialized with valid group_index or rep_index.
bool is_identity() const
Returns true if SymGroupRepID corresponds to an Identity representation.
Generalized symmetry matrix representation for arbitrary dimension Can be used to describe applicatio...
Definition: SymMatrixXd.hh:26
SymOp is the Coordinate representation of a symmetry operation it keeps fraction (FRAC) and Cartesian...
Definition: SymOp.hh:28
const matrix_type & matrix() const
Const access of entire cartesian symmetry matrix.
Definition: SymOp.hh:60
SymOp inverse() const
get the inverse of this SymOp
Definition: SymOp.cc:87
bool time_reversal() const
Const access of the time-reversal flag (true if operation reverses time)
Definition: SymOp.hh:66
const double & map_error() const
Allows access to the map_error.
Definition: SymOp.cc:12
const vector_type & tau() const
Const access of the cartesian translation vector, 'tau'.
Definition: SymOp.hh:63
static SymOp translation(const Eigen::Ref< const vector_type > &_tau)
static method to create operation that describes pure translation
Definition: SymOp.hh:34
SymOpRepresentation is the base class for anything describes a symmetry operation.
SymPermutation describes how a symmetry operation permutes a list of 'things' For example,...
static std::string NAME()
get a string with the name of the active mode
Represents cartesian and fractional coordinates.
Definition: Coordinate.hh:34
bool is_within() const
Checks to see if coordinate is in the unit cell, but does not translate it.
Definition: Coordinate.cc:244
Coordinate_impl::CartCoordinate cart()
Set Cartesian coordinate vector and update fractional coordinate vector.
Definition: Coordinate.hh:562
const vector_type & const_frac() const
user override to force const Access the fractional coordinate vector
Definition: Coordinate.hh:68
double min_dist(const Coordinate &neighbor) const
Returns distance (in Angstr) to nearest periodic image of neighbor.
Definition: Coordinate.cc:152
Coordinate_impl::FracCoordinate frac()
Set the fractional coordinate vector.
Definition: Coordinate.hh:550
const vector_type & const_cart() const
user override to force const Access the Cartesian coordinate vector
Definition: Coordinate.hh:90
const Eigen::Matrix3d & lat_column_mat() const
3x3 matrix with lattice vectors as its columne
Definition: Lattice.hh:110
double tol() const
Definition: Lattice.hh:195
const Eigen::Matrix3d & inv_lat_column_mat() const
Inverse of Lattice::lat_column_mat() It is the transformation matrix 'C2F', such that f = C2F * c whe...
Definition: Lattice.hh:117
std::string to_string(ENUM val)
Return string representation of enum class.
Definition: io_traits.hh:172
double angle(const Eigen::Ref< const Eigen::Vector3d > &a, const Eigen::Ref< const Eigen::Vector3d > &b)
Get angle, in radians, between two vectors on range [0,pi].
Eigen::CwiseUnaryOp< decltype(Local::round_l< typename Derived::Scalar >), const Derived > round(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd.
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.
bool compare_periodic(const SymOp &a, const SymOp &b, const Lattice &lat, PERIODICITY_TYPE periodicity, double _tol)
Definition: SymGroup.cc:2160
MasterSymGroup make_master_sym_group(SymGroup const &_group, Lattice const &_lattice)
Definition: SymGroup.cc:2148
SymOp within_cell(const SymOp &a, const Lattice &lat, PERIODICITY_TYPE periodicity)
Definition: SymGroup.cc:2178
std::map< std::string, std::string > point_group_info(SymGroup const &group)
return dictionary of point group info: result["centricity"] : "Centric" or "Acentric" result["crystal...
Definition: SymGroup.cc:882
static std::vector< Index > _number_of_operation_types(SymGroup const &group)
Definition: SymGroup.cc:26
static std::map< std::string, std::string > _centric_point_group_info(std::vector< Index > const &op_types)
Definition: SymGroup.cc:49
std::map< std::string, std::string > _acentric_point_group_info(std::vector< Index > const &op_types)
Definition: SymGroup.cc:154
static std::map< std::string, std::string > _nonmagnetic_point_group_info(SymGroup const &g)
Definition: SymGroup.cc:334
IdentitySymRepBuilder Identity()
std::vector< SymOp > make_point_group(Lattice const &_lat)
Populate.
Definition: SymTools.cc:113
std::vector< SymOp > SymOpVector
Main CASM namespace.
Definition: APICommand.hh:8
bool almost_equal(ClusterInvariants const &A, ClusterInvariants const &B, double tol)
Check if ClusterInvariants are equal.
Eigen::MatrixXd MatrixXd
std::string description(const SymOp &op, const xtal::Lattice &lat, SymInfoOptions opt=SymInfoOptions())
Print SymInfo to string.
COORD_TYPE
Definition: enum.hh:6
Index find_index(Iterator begin, Iterator end, const T &value)
Equivalent to std::distance(begin, std::find(begin, end, value))
Definition: algorithm.hh:24
Eigen::Matrix3d Matrix3d
void swap(ConfigDoF &A, ConfigDoF &B)
Definition: ConfigDoF.cc:260
SymGroupRep coord_transformed_copy(SymGroupRep const &_rep, const Eigen::MatrixXd &trans_mat)
Make a copy of representation on vector space 'V' that is transformed into a representation on vector...
Definition: SymGroupRep.cc:175
const COORD_TYPE FRAC
Definition: enum.hh:8
const double TOL
Definition: definitions.hh:30
const PERIODICITY_TYPE PERIODIC
Definition: enum.hh:20
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:104
bool float_lexicographical_compare(const Eigen::Ref< const Eigen::MatrixXd > &A, const Eigen::Ref< const Eigen::MatrixXd > &B, double tol)
Floating point lexicographical comparison with tol.
PERIODICITY_TYPE
Definition: enum.hh:13
Iterator find(Iterator begin, Iterator end, const T &value, BinaryCompare q)
Equivalent to std::find(begin, end, value), but with custom comparison.
Definition: algorithm.hh:16
bool contains(const Container &container, const T &value)
Equivalent to container.end() != std::find(container.begin(), container.end(), value)
Definition: algorithm.hh:83
const COORD_TYPE CART
Definition: enum.hh:9
bool valid_index(Index i)
Definition: definitions.cc:5
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
Log & err_log()
Definition: Log.hh:426
ProjectSettings & set
Definition: settings.cc:137
Simple struct to be used as return type for SymOp::info().
Definition: SymInfo.hh:26
double angle
Definition: SymInfo.hh:42
xtal::Coordinate axis
Definition: SymInfo.hh:38
symmetry_type op_type
Definition: SymInfo.hh:31
xtal::Coordinate location
A Cartesian coordinate that is invariant to the operation (if one exists)
Definition: SymInfo.hh:49