27 std::vector<Index> result(20, 0);
28 for (
SymOp const &op : group) {
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]++;
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) {
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) {
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) {
66 result[
"crystal_system"] =
"Hexagonal";
67 if (op_types[2] == 1) {
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) {
73 result[
"international_name"] =
"6/mmm";
74 result[
"name"] =
"D6h";
75 result[
"latex_name"] =
"D_{6h}";
76 result[
"space_group_range"] =
"191-194";
81 else if (op_types[4] == 2) {
82 result[
"crystal_system"] =
"Rhombohedral";
83 if (op_types[2] == 0) {
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) {
89 result[
"international_name"] =
"-3m";
90 result[
"name"] =
"D3d";
91 result[
"latex_name"] =
"D_{3d}";
92 result[
"space_group_range"] =
"162-167";
97 else if (op_types[6] == 2) {
98 result[
"crystal_system"] =
"Tetragonal";
99 if (op_types[2] == 1) {
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) {
105 result[
"international_name"] =
"4/mmm";
106 result[
"name"] =
"D4h";
107 result[
"latex_name"] =
"D_{4h}";
108 result[
"space_group_range"] =
"123-142";
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";
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";
129 for (
Index m : op_types) {
133 result[
"crystal_system"] =
"Triclinic";
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";
145 if (is_error || result[
"crystal_system"].empty()) {
146 throw std::runtime_error(
147 "Error finding centric point group type. Crystal system determined to "
149 result[
"crystal_system"]);
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) {
159 result[
"crystal_system"] =
"Cubic";
160 if (op_types[6] == 0) {
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) {
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) {
171 result[
"international_name"] =
"-43m";
172 result[
"name"] =
"Td";
173 result[
"latex_name"] =
"T_d";
174 result[
"space_group_range"] =
"215-220";
179 else if (op_types[5] == 2) {
180 result[
"crystal_system"] =
"Hexagonal";
181 if (op_types[2] == 0) {
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) {
187 result[
"international_name"] =
"-6m2";
188 result[
"name"] =
"D3h";
189 result[
"latex_name"] =
"D_{3h}";
190 result[
"space_group_range"] =
"187-190";
194 else if (op_types[10] == 2) {
195 result[
"crystal_system"] =
"Hexagonal";
196 if (op_types[2] == 7) {
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) {
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) {
207 result[
"international_name"] =
"6";
208 result[
"name"] =
"C6 (Chiral)";
209 result[
"latex_name"] =
"C_6";
210 result[
"space_group_range"] =
"168-173";
215 else if (op_types[4] == 2) {
216 result[
"crystal_system"] =
"Rhombohedral";
217 if (op_types[2] == 3) {
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) {
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";
236 else if (op_types[6] == 2) {
237 result[
"crystal_system"] =
"Tetragonal";
238 if (op_types[2] == 5) {
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) {
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) {
249 result[
"international_name"] =
"4";
250 result[
"name"] =
"C4 (Chiral)";
251 result[
"latex_name"] =
"C_4";
252 result[
"space_group_range"] =
"75-80";
257 else if (op_types[7] == 2) {
258 result[
"crystal_system"] =
"Tetragonal";
259 if (op_types[2] == 3) {
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) {
265 result[
"international_name"] =
"-4";
266 result[
"name"] =
"S4";
267 result[
"latex_name"] =
"S_4";
268 result[
"space_group_range"] =
"81-82";
273 else if ((op_types[2] + op_types[3]) == 3) {
274 result[
"crystal_system"] =
"Orthorhomic";
275 if (op_types[2] == 3) {
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) {
281 result[
"international_name"] =
"mm2";
282 result[
"name"] =
"C2v";
283 result[
"latex_name"] =
"C_{2v}";
284 result[
"space_group_range"] =
"25-46";
289 else if ((op_types[2] + op_types[3]) == 1) {
290 result[
"crystal_system"] =
"Monoclinic";
291 if (op_types[2] == 1) {
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) {
297 result[
"international_name"] =
"m";
298 result[
"name"] =
"Cs";
299 result[
"latex_name"] =
"C_s";
300 result[
"space_group_range"] =
"6-9";
307 for (
Index m : op_types) {
311 result[
"crystal_system"] =
"Triclinic";
314 result[
"international_name"] =
"1";
315 result[
"name"] =
"C1 (Chiral)";
316 result[
"latex_name"] =
"C_1";
317 result[
"space_group_range"] =
"1";
323 if (is_error || result[
"crystal_system"].empty()) {
324 throw std::runtime_error(
325 "Error finding acentric point group type. Crystal system determined to "
327 result[
"crystal_system"]);
338 std::map<std::string, std::string> result;
340 Index nm = op_types[2] + 1;
341 for (
Index k = 4; k < op_types.size(); k++) {
346 result[
"centricity"] =
"Centric";
349 result[
"centricity"] =
"Acentric";
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) {
374 for (
Index i = 0; i < size(); i++) at(i).set_index(*
this, i);
386 SymGroup::operator=(RHS);
393 for (
Index i = 0; i < size(); i++) at(i).set_index(*
this, i);
403 back().set_index(*
this, size() - 1);
461 for (
Index i = 0; i < size(); i++) {
481 Index op_index)
const {
496 for (
Index i = 0; i < size(); i++)
510 for (
Index i = 0; i < size(); i++) {
511 for (
Index j = 0; j < size(); j++) {
512 for (
Index k = 0; k < size(); k++) {
514 regrep_mat(j, k) = 1.0;
516 regrep_mat(j, k) = 0.0;
538 for (
Index i = 0; i < size(); i++) {
544 kroneckerProduct(*(rep1->MatrixXd(i)), *(rep2->
MatrixXd(i)), tmat);
554 const std::vector<SymGroupRepID> &rep_IDs)
const {
555 std::vector<SymGroupRep const *> treps;
556 for (
Index i = 0; i < rep_IDs.size(); i++) {
563 for (
Index i = 0; i < treps.size(); i++) {
567 dim += (treps[i]->MatrixXd(0))->cols();
572 for (
Index i = 0; i < size(); i++) {
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();
596 for (
Index i = 0; i < size(); i++) {
602 coord_rep_mat *= coord_rep_mat.determinant();
606 Eigen::Quaterniond opq(coord_rep_mat);
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();
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();
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();
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();
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();
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();
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();
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();
675 for (
Index i = 0; i < new_rep->size(); i++) {
712 m_rep_array.back()->set_master_group(*
this, new_ID);
726 throw std::runtime_error(
727 "Attempting to access representation from MasterGroup #" +
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);
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]; });
762 ->set_identifiers(*
this,
m_rep_array[i]->symrep_ID(),
783 lattice_point_group_operations, _lat);
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";
808 : m_lat_ptr(_lat_ptr), m_group_periodicity(init_type), m_max_error(-1) {
819 std::vector<SymOp>::push_back(new_op);
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));
863 ind_array[i] = at(i).index();
872 std::vector<SymOp>::clear();
886 for (
SymOp const &op : pg) {
887 if (!op.time_reversal()) {
889 }
else if (!grey && op.matrix().isIdentity(
TOL)) {
897 if (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(
'_'),
"'");
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"] +
")");
932 for (
Index i = 0; i < size(); i++) {
933 SymOp tsymop(at(i).no_trans());
934 if (keep_repeated || !
contains(result, tsymop)) {
952 "Attempting to access Lattice of a SymGroup, but it has not been "
979 std::vector<Eigen::Vector3d> highsym_axes;
980 std::vector<int> mult;
995 std::vector<SymInfo>
info;
1011 if (
name ==
"C1h") {
1023 highsym_axes.clear();
1026 for (
Index i = 0; i < size(); i++) {
1030 info[i].axis.const_cart())) {
1034 highsym_axes.push_back(
info[i].axis.cart());
1040 Eigen::Vector3d hs_axis;
1041 bool hs_axis_set =
false;
1042 double hangle = 360;
1044 for (
Index i = 0; i < size(); i++) {
1052 int order = *std::max_element(mult.begin(), mult.end());
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);
1069 if (
name ==
"D3d") {
1070 for (
int i =
int(mult.size()) - 1; i >= 0; i--) {
1072 throw std::runtime_error(
1073 "Error in _generate_class_names: using hs_axis unitialized");
1076 highsym_axes.erase(highsym_axes.begin() + i);
1077 mult.erase(mult.begin() + i);
1084 std::string cprime =
"'";
1085 std::string sprime =
"'";
1086 std::string vprime =
"";
1088 for (
Index i = 0; i < size(); i++) {
1091 std::ostringstream
s;
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());
1176 std::string one =
"1";
1184 if (
name ==
"D2h") {
1188 Eigen::Vector3d::UnitX())) {
1191 Eigen::Vector3d::UnitY())) {
1194 Eigen::Vector3d::UnitY())) {
1200 Eigen::Vector3d::UnitX())) {
1203 Eigen::Vector3d::UnitY())) {
1206 Eigen::Vector3d::UnitZ())) {
1232 bool all_commute =
true;
1245 all_commute =
false;
1260 for (
Index i = 0; i < size(); i++) {
1267 for (
Index i = 0; i < size(); i++) {
1273 }
while (telem != i);
1282 std::vector<std::set<std::set<Index>>> result;
1290 result.push_back({{0}});
1293 std::set<Index> tgroup({0, i});
1301 for (
auto const &orbit : result) {
1302 if (orbit.begin()->size() == tgroup.size() && orbit.count(tgroup) > 0) {
1310 result.push_back({});
1316 for (
auto const &coset :
left_cosets(tgroup.begin(), tgroup.end())) {
1317 std::set<Index> tequiv;
1318 for (
Index op : tgroup) {
1320 tequiv.insert(
ind_prod(coset[0], tempind));
1322 result.back().insert(std::move(tequiv));
1340 Index i, k, ii, jj, tempind;
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;
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++) {
1356 if (tgroup.insert(prod).second) {
1357 vgroup.push_back(prod);
1363 if (
m_subgroups[k].begin()->size() == tgroup.size() &&
1375 for (
auto const &coset :
left_cosets(tgroup.begin(), tgroup.end())) {
1376 std::set<Index> tequiv;
1377 for (
Index op : tgroup) {
1379 tequiv.insert(
ind_prod(coset[0], tempind));
1406 std::vector<std::string> sg_names, sg_names_limited;
1407 std::vector<bool> chosen_flag(
m_subgroups.size(),
false);
1415 sg_names.push_back(sgroup.
get_name());
1418 std::vector<std::vector<Index>> sg_tree(
m_subgroups.size(),
1419 std::vector<Index>());
1426 for (
auto const &op : equiv) {
1433 sg_tree[i].push_back(j);
1464 std::vector<SymGroup> unique_sgroups;
1467 if (chosen_flag[i])
continue;
1468 unique_sgroups.push_back(
SymGroup());
1470 unique_sgroups.back().push_back(at(op));
1472 unique_sgroups.back().sort();
1475 return unique_sgroups;
1496 for (
Index i = 0; i < size(); i++) {
1497 bool dup_class(
false);
1504 if (dup_class)
continue;
1508 for (
Index j = 0; j < size(); j++) {
1574 "Attempting to set ID for out-of-bounds irrep.");
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"
1597 return at(0).master_group().coord_rep_ID();
1602 if (!size() || !at(0).has_valid_master()) {
1603 err_log() <<
"CRITICAL ERROR: In SymGroup::allocate_representation(), "
1604 "SymGroup is improperly initialized.\n"
1609 return at(0).master_group().allocate_representation();
1616 throw std::runtime_error(std::string(
"Cannot find irrep ") +
1619 return at(0).master_group().representation(
irrep_IDs[i]);
1626 const std::vector<SymOp> &subgroup,
double tol)
const {
1628 return left_cosets(sg_inds.begin(), sg_inds.end());
1655 multi_table.resize(size(), std::vector<Index>(size(), -1));
1675 <<
"WARNING: In SymGroup::get_name(), unable to get symgroup type.\n";
1676 err_log() <<
"group size is " << size() <<
'\n';
1704 multi_table.resize(size(), std::vector<Index>(size(), -1));
1706 for (i = 0; i < size(); i++) {
1707 for (j = 0; j < size(); j++) {
1725 err_log() <<
"Failed to construc multiplication table! Table in "
1734 multi_table.resize(size(), std::vector<Index>(size(), -1));
1768 for (
Index i = 0; i < size(); i++) {
1780 for (
Index i = 0; i < size(); i++) {
1791 const std::vector<SymOp> &subgroup,
double tol)
const {
1792 std::vector<Index> tarray;
1793 for (
Index i = 0; i < subgroup.size(); i++) {
1795 if (tarray.back() == size()) {
1810 for (
Index i = 0; i < size(); i++) {
1811 for (
Index j = 0; j < size(); j++) {
1824 while (new_ops && size() < max_size) {
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());
1831 SymOp tOp(A_op * B_op);
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";
1876 <<
" representation of group containing " << size() <<
" elements:\n\n";
1879 for (
Index i = 0; i < size(); i++) {
1881 at(i).print(out, c2f_mat);
1891 if (!size())
return;
1893 Eigen::Vector3i max_trans(3, 3, 3);
1895 space_group_cell.
clear();
1897 std::vector<SymInfo> sg_info;
1898 for (
Index i = 0; i < size(); i++) {
1900 Eigen::Vector3i::Ones());
1902 trans.
frac() = lat_comb().cast<
double>();
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;
1921 sg_info.push_back(
info);
1923 }
while (++lat_comb);
1933 Eigen::Vector3i min_trans,
1934 Eigen::Vector3i max_trans)
const {
1935 if (!size())
return;
1939 for (
Index i = 0; i < size(); i++) {
1941 Eigen::Vector3i::Ones());
1943 trans.
frac() = lat_comb().cast<
double>();
1947 if (!
contains(space_group, new_sym)) {
1951 }
while (++lat_comb);
1963 stream <<
"Locations for symmetry operations\n";
1967 for (
Index i = 0; i < size(); i++) {
1969 at(i).print(stream, c2f_mat);
1971 stream << std::endl;
1973 stream << std::endl;
1975 stream <<
"Location:" << std::endl;
1976 stream <<
"FRAC\t\t\t\t\tCART" << std::endl;
1981 stream << std::endl;
1983 if (i + 1 < size()) {
1991 stream <<
"------------------------------------------------------------"
1992 "----------------------\n\n";
2023 typedef Eigen::Matrix<double, 10, 1> key_type;
2024 auto make_key = [](
const SymOp &op,
const Lattice &lat) {
2032 vec[offset] = -op.
matrix().determinant();
2035 vec[offset] = -op.
matrix().trace();
2051 auto op_compare = [tol](
const key_type &A,
const key_type &B) {
2055 typedef std::map<key_type,
SymOp,
2056 std::reference_wrapper<decltype(op_compare)>>
2060 auto cclass_compare = [tol](
const map_type &A,
const map_type &B) {
2067 std::set<map_type, std::reference_wrapper<decltype(cclass_compare)>> sorter(
2071 for (
int i = 0; i < size(); ++i) {
2072 if (at(i).is_identity()) {
2085 map_type cclass(op_compare);
2088 cclass.insert(std::make_pair(make_key(op,
lattice()), op));
2091 sorter.emplace(std::move(cclass));
2095 map_type all_op(op_compare);
2096 for (
auto it = begin(); it != end(); ++it) {
2097 all_op.emplace(make_key(*it,
lattice()), *it);
2099 sorter.emplace(std::move(all_op));
2104 for (
auto const &cclass : sorter) {
2105 for (
auto it = cclass.begin(); it != cclass.end(); ++it) {
2119 for (
Index i = 0; i < size(); i++) {
2120 tvalue += (at(i).matrix().trace()) * (at(i).matrix().trace());
2123 if (
Index(std::abs(tvalue)) == size()) {
2133 const Eigen::Ref<const SymOp::vector_type> &shift) {
2134 for (
Index ng = 0; ng < size(); ng++) at(ng) += shift;
2141 const Eigen::Ref<const SymOp::vector_type> &shift) {
2142 for (
Index ng = 0; ng < size(); ng++) at(ng) -= shift;
2152 for (
auto const &op : _group) {
2180 if (periodicity !=
PERIODIC)
return a;
std::set< std::string > & s
A Counter allows looping over many incrementing variables in one loop.
SymGroup m_point_group
Copy of *this with translations removed.
SymGroupRepID allocate_representation() const
Add a new empty representation.
SymGroupRepID add_kronecker_rep(SymGroupRepID ID1, SymGroupRepID ID2) const
SymGroupRep * _representation_ptr(SymGroupRepID _id) const
void sort()
Sort SymOp in the SymGroup.
void set_rep(SymGroupRepID _rep_ID, SymOpRepresentation const &_op_rep, Index op_index) const
SymGroupRepID reg_rep_ID() const
SymGroupRepID _add_representation(SymGroupRep *_rep_ptr) const
const SymGroup & point_group() const
void push_back(const SymOp &op)
MasterSymGroup(PERIODICITY_TYPE init_type=PERIODIC)
MasterSymGroup & operator=(const MasterSymGroup &RHS)
SymGroupRep const & representation(SymGroupRepID i) const
Const access of alternate Representations of a SymGroup.
SymGroupRepID identity_rep_ID(Index dim) const
std::vector< SymGroupRepID > m_identity_rep_IDs
SymGroupRepID coord_rep_ID() const
SymGroupRepID add_representation(const SymGroupRep &new_rep) const
SymGroupRepID add_rotation_rep() const
std::vector< SymGroupRep * > m_rep_array
SymGroupRep const & coord_rep() const
SymGroupRepID add_direct_sum_rep(const std::vector< SymGroupRepID > &rep_IDs) const
SymGroupRepID m_coord_rep_ID
ID of Cartesian representation.
SymGroupRepID m_reg_rep_ID
SymGroupRepID add_transformed_rep(SymGroupRepID orig_ID, const Eigen::MatrixXd &trans_mat) const
SymGroupRepID _add_coord_rep() const
Index group_index() const
SymGroupRep const & reg_rep() const
SymGroupRepID _add_reg_rep() const
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
Lattice const * m_lat_ptr
Pointer to a lattice for doing periodic comparisons.
std::vector< SymGroup > unique_subgroups() const
bool is_irreducible() const
const std::string & get_latex_name() const
std::vector< Index > op_indices() const
SymGroup & apply_sym(const SymOp &op)
Calls 'apply_sym' on all SymOps in the group.
std::vector< std::set< std::set< Index > > > _small_subgroups() const
const std::vector< std::set< std::set< Index > > > & subgroups() const
PERIODICITY_TYPE periodicity() const
double max_error()
This returns the group's max_error.
SymGroup & operator-=(const Eigen::Ref< const SymOp::vector_type > &shift)
SymGroupRepID coord_rep_ID() const
const std::string & get_name() const
virtual void clear_tables()
void _generate_subgroups() const
bool contains_periodic(const SymOp &test_op, double tol=TOL) const
Check to see if a SymOp is contained in in SymGroup.
multivector< Index >::X< 2 > alt_multi_table
Index ind_inverse(Index i) const
Get index of operation that is inverse of operation at(i)
void print(std::ostream &out, COORD_TYPE mode) const
Print the SymGroup to a stream.
std::vector< std::vector< Index > > conjugacy_classes
std::vector< SymGroupRepID > irrep_IDs
bool _generate_multi_table() const
void _generate_elem_order_table() const
SymGroup(PERIODICITY_TYPE init_type=PERIODIC)
Initialize by setting periodicity mode (default mode is PERIODIC)
multivector< Index >::X< 2 > elem_order_table
const std::vector< std::vector< Index > > & get_alt_multi_table() const
const std::vector< std::vector< Index > > & get_multi_table() const
virtual void sort()
Sort SymOp in the SymGroup.
bool is_group(double tol=TOL) const
Check to see if SymGroup satisfies the group property.
Index ind_prod(Index i, Index j) const
Get index of operation that is result of multiplication of at(i)*at(j)
std::vector< std::string > class_names
std::vector< Index > master_group_indices() const
Return the MasterSymGroup indices of the operations in this SymGroup.
virtual void push_back(const SymOp &new_op)
Index class_of_op(Index i) const
Get conjugacy class index of operation at(i)
void calc_space_group_in_range(SymGroup &space_group, const Lattice &_cell, Eigen::Vector3i min_trans, Eigen::Vector3i max_trans) const
SymGroup copy_no_trans(bool keep_repeated=false) const
Fill up a SymGroup with *this minus the shifts.
void _generate_class_names() const
Index find_periodic(const SymOp &test_op, double tol=TOL) const
const std::vector< std::vector< Index > > & get_conjugacy_classes() const
void set_lattice(const Lattice &new_lat)
Lattice used for periodic comparisons (for instance, to generate multiplcation table)
std::vector< Index > find_all_periodic(const std::vector< SymOp > &subgroup, double tol=TOL) const
void enforce_group(double tol=TOL, Index max_size=200)
Enforce group property by adding products of operations to the group.
void _generate_centralizers() const
SymInfo info(Index i) const
void set_irrep_ID(Index i, SymGroupRepID ID) const
set symrep ID of a particular irrep
void calc_space_group_in_cell(SymGroup &space_group, const Lattice &_cell) const
void print_locations(std::ostream &stream) const
print locations of the symmetry-generating element of each SymOp
void _generate_alt_multi_table() const
SymGroupRepID allocate_representation() const
Add a new empty representation.
Index find_no_trans(const SymOp &test_op) const
Check to see if a SymOp is contained in in SymGroup and return its index.
const Lattice & lattice() const
Lattice used for periodic comparisons (for instance, to generate multiplcation table)
std::vector< std::vector< Index > > left_cosets(const std::vector< SymOp > &subgroup, double tol=TOL) const
multivector< Index >::X< 2 > multi_table
multi_table[i][j] gives index of operation that is result of at(i)*at(j)
multivector< Index >::X< 2 > centralizer_table
std::vector< Index > index2conjugacy_class
static SymGroup lattice_point_group(Lattice const &_lat)
SymGroupRepID get_irrep_ID(Index i) const
Get symrep ID of a particular irrep.
std::vector< std::set< std::set< Index > > > m_subgroups
SymGroup & operator+=(const Eigen::Ref< const SymOp::vector_type > &shift)
Cartesian translation of SymGroup origin by vector 'shift'.
void invalidate_multi_tables() const
void _generate_conjugacy_classes() const
SymGroupRep const & get_irrep(Index i) const
Get symrep for a particular irrep.
SymGroupRep is an alternative representation of a SymGroup for something other than real space....
SymGroupRep * copy() const
Returns pointer to unmanaged copy of this SymGroupRep.
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 ...
Eigen::MatrixXd const * MatrixXd(Index i) const
pointer to MatrixXd corresponding to SymOpRepresentation at entry 'i' of this SymGroupRep Returns nul...
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...
SymOp is the Coordinate representation of a symmetry operation it keeps fraction (FRAC) and Cartesian...
const matrix_type & matrix() const
Const access of entire cartesian symmetry matrix.
SymOp inverse() const
get the inverse of this SymOp
bool time_reversal() const
Const access of the time-reversal flag (true if operation reverses time)
const double & map_error() const
Allows access to the map_error.
const vector_type & tau() const
Const access of the cartesian translation vector, 'tau'.
static SymOp translation(const Eigen::Ref< const vector_type > &_tau)
static method to create operation that describes pure translation
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.
bool is_within() const
Checks to see if coordinate is in the unit cell, but does not translate it.
Coordinate_impl::CartCoordinate cart()
Set Cartesian coordinate vector and update fractional coordinate vector.
const vector_type & const_frac() const
user override to force const Access the fractional coordinate vector
double min_dist(const Coordinate &neighbor) const
Returns distance (in Angstr) to nearest periodic image of neighbor.
Coordinate_impl::FracCoordinate frac()
Set the fractional coordinate vector.
const vector_type & const_cart() const
user override to force const Access the Cartesian coordinate vector
const Eigen::Matrix3d & lat_column_mat() const
3x3 matrix with lattice vectors as its columne
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...
std::string to_string(ENUM val)
Return string representation of enum class.
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)
MasterSymGroup make_master_sym_group(SymGroup const &_group, Lattice const &_lattice)
SymOp within_cell(const SymOp &a, const Lattice &lat, PERIODICITY_TYPE periodicity)
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...
static std::vector< Index > _number_of_operation_types(SymGroup const &group)
static std::map< std::string, std::string > _centric_point_group_info(std::vector< Index > const &op_types)
std::map< std::string, std::string > _acentric_point_group_info(std::vector< Index > const &op_types)
static std::map< std::string, std::string > _nonmagnetic_point_group_info(SymGroup const &g)
IdentitySymRepBuilder Identity()
std::vector< SymOp > make_point_group(Lattice const &_lat)
Populate.
std::vector< SymOp > SymOpVector
bool almost_equal(ClusterInvariants const &A, ClusterInvariants const &B, double tol)
Check if ClusterInvariants are equal.
std::string description(const SymOp &op, const xtal::Lattice &lat, SymInfoOptions opt=SymInfoOptions())
Print SymInfo to string.
Index find_index(Iterator begin, Iterator end, const T &value)
Equivalent to std::distance(begin, std::find(begin, end, value))
void swap(ConfigDoF &A, ConfigDoF &B)
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...
const PERIODICITY_TYPE PERIODIC
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
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.
Iterator find(Iterator begin, Iterator end, const T &value, BinaryCompare q)
Equivalent to std::find(begin, end, value), but with custom comparison.
bool contains(const Container &container, const T &value)
Equivalent to container.end() != std::find(container.begin(), container.end(), value)
bool valid_index(Index i)
INDEX_TYPE Index
For long integer indexing:
Simple struct to be used as return type for SymOp::info().
xtal::Coordinate location
A Cartesian coordinate that is invariant to the operation (if one exists)