CASM  1.1.0
A Clusters Approach to Statistical Mechanics
SymTools.cc
Go to the documentation of this file.
2 
4 #include "casm/misc/algorithm.hh"
5 
6 namespace {
8 
9 // TODO
10 // I removed this from the library, because it seems like something that exists
11 // solely for generating the point group If you need this routine somewhere
12 // else, go right ahead and put it back in the xtal namespace, and uncomment its
13 // declaration in SymTools.hh
17 Lattice symmetrized_with_fractional(
18  const Lattice &lattice,
19  const std::vector<Eigen::Matrix3i> &fractional_point_group) {
20  Eigen::Matrix3d symmetrized_lat_matrix_squared(Eigen::Matrix3d::Zero());
21 
22  // This loop performs the Reynolds operator on the input lattice
23  for (const auto &frac_mat : fractional_point_group) {
24  symmetrized_lat_matrix_squared += frac_mat.cast<double>().transpose() *
25  lattice.lat_column_mat().transpose() *
26  lattice.lat_column_mat() *
27  frac_mat.cast<double>();
28  }
29  symmetrized_lat_matrix_squared /= double(fractional_point_group.size());
30 
31  // symmetrized_lat_matrix_squared has the symmetrized lengths and angles -- it
32  // is equal to symmetrized_L.transpose()*symmetrized_L we will find the sqrt
33  // of symmetrized_lat_matrix_squared and then reorient it so that it matches
34  // the original lattice
35  Eigen::Matrix3d symmetrized_lat_matrix_misoriented;
36  // This decomposition does the following transformation:
37  // symmetrized_lat_matrix_squared = U * S * V.transpose()
38  Eigen::JacobiSVD<Eigen::Matrix3d> singular_value_decomposition(
39  symmetrized_lat_matrix_squared,
40  Eigen::ComputeFullU | Eigen::ComputeFullV);
41 
42  // symmetrized_lat_matrix_misoriented is sqrt of symlat.transpose()*symlat
43  // symmetrized_lat_matrix_misoriented = U * sqrt(S) * V.transpose() = R *
44  // symmetrized_L = R * X * input_L R * X * input_L =
45  // symmetrized_lat_matrix_misoriented R * X =
46  // symmetrized_lat_matrix_misoriented * input_L.inverse()
47  symmetrized_lat_matrix_misoriented =
48  singular_value_decomposition.matrixU() *
49  singular_value_decomposition.singularValues().cwiseSqrt().asDiagonal() *
50  singular_value_decomposition.matrixV().transpose();
51 
52  // if starting lattice were perfect, we would have origlat=rotation*tMat
53  // R * X = symmetrized_lat_matrix_misoriented * input_L.inverse()
54  // R * X = symmetrized_lat_matrix_misoriented * input_L.inverse() = A * S' *
55  // B.transpose() X = B * S' * B.transpose() due to X = X.transpose() R = A *
56  // B.transpose()
57  singular_value_decomposition.compute(symmetrized_lat_matrix_misoriented *
58  lattice.inv_lat_column_mat());
59 
60  // symmetrized_lat_matrix_misoriented = R * symmetrized_L
61  // R.transpose() = R.inverse() because R is a rotation
62  // R.transpose()= B * A.transpose()
63  // symmetrized_L = B * A.transpose() * symmetrized_lat_matrix_misoriented
64  Eigen::Matrix3d symmetrized_lat_matrix =
65  singular_value_decomposition.matrixV() *
66  singular_value_decomposition.matrixU().transpose() *
67  symmetrized_lat_matrix_misoriented;
68 
69  return Lattice(symmetrized_lat_matrix, lattice.tol());
70 }
71 } // namespace
72 
73 namespace CASM {
74 namespace sym {
76  lat = Lattice(get_matrix(op) * lat.lat_column_mat(), lat.tol());
77  return lat;
78 }
79 
81  apply(op, lat_copy);
82  return lat_copy;
83 }
84 } // namespace sym
85 
86 namespace xtal {
88 std::vector<Index> invariant_subgroup_indices(
89  const Lattice &lat, std::vector<SymOp> const &super_grp) {
90  std::vector<Index> result;
91  invariant_subgroup_indices(lat, super_grp, std::back_inserter(result));
92  return result;
93 }
94 
96  const std::vector<SymOp> &enforced_group) {
97  Eigen::Matrix3i frac_mat;
98  std::vector<Eigen::Matrix3i> fractional_point_group;
99  for (Index ng = 0; ng < enforced_group.size(); ng++) {
100  frac_mat =
101  iround(lattice.inv_lat_column_mat() * get_matrix(enforced_group[ng]) *
102  lattice.lat_column_mat());
103  fractional_point_group.push_back(frac_mat);
104  }
105  return symmetrized_with_fractional(lattice, fractional_point_group);
106 }
107 
108 Lattice symmetrize(const Lattice &lattice, double point_group_tolerance) {
109  auto point_group = make_point_group(lattice, point_group_tolerance);
110  return symmetrize(lattice, point_group);
111 }
112 
113 std::vector<SymOp> make_point_group(Lattice const &_lat) {
114  return make_point_group(_lat, _lat.tol());
115 }
116 
117 std::vector<SymOp> make_point_group(Lattice const &_lat, double tol) {
118  std::vector<Eigen::Matrix3i> frac_point_group;
119  frac_point_group.reserve(48);
120 
121  // Enumerate all possible matrices with elements equal to -1, 0, or 1
122  // These represent operations that reorder lattice vectors or replace one
123  // or more lattice vectors with a face or body diagonal.
124 
125  // For this algorithm to work, lattice needs to be in reduced form.
126  Lattice tlat_reduced(_lat.reduced_cell());
127  tlat_reduced.set_tol(tol);
128  IsPointGroupOp is_equiv(tlat_reduced);
129  for (Eigen::Matrix3i const &mat : unimodular_matrices()) {
130  if (is_equiv(mat)) {
131  frac_point_group.push_back(mat);
132  }
133  }
134 
135  // Find group closure using fractional form (skip for groups sizes that are
136  // very unlikely to be unconverged)
137  if (frac_point_group.size() != 48 && frac_point_group.size() != 24) {
138  Eigen::Matrix3i t_op;
139  for (Index i = 0; i < frac_point_group.size(); ++i) {
140  t_op = inverse(frac_point_group[i]);
141  if (!contains(frac_point_group, t_op)) {
142  frac_point_group.push_back(t_op);
143  }
144  for (Index j = i; j < frac_point_group.size(); ++j) {
145  t_op = frac_point_group[i] * frac_point_group[j];
146  if (!contains(frac_point_group, t_op)) {
147  frac_point_group.push_back(t_op);
148  }
149  }
150  }
151  }
152 
153  // Convert the fractional representation to cartesian and return as SymOp
154  std::vector<SymOp> result;
155  result.reserve(frac_point_group.size());
156  Eigen::Matrix3d t_cart, t_diff;
157  Lattice symlat = symmetrized_with_fractional(tlat_reduced, frac_point_group);
158  for (Eigen::Matrix3i const &frac : frac_point_group) {
159  t_cart = symlat.lat_column_mat() * frac.cast<double>() *
160  symlat.inv_lat_column_mat();
161  t_diff = t_cart * _lat.lat_column_mat() - _lat.lat_column_mat();
162  result.push_back(SymOp::point_operation(t_cart));
163  }
164  return result;
165 }
166 
167 } // namespace xtal
168 
169 } // namespace CASM
Checks if operations are point group operations.
const Eigen::Matrix3d & lat_column_mat() const
3x3 matrix with lattice vectors as its columne
Definition: Lattice.hh:110
void set_tol(double _tol)
Definition: Lattice.hh:197
double tol() const
Definition: Lattice.hh:195
Lattice reduced_cell() const
Find the lattice vectors which give most compact unit cell Compactness is measured by how close lat_c...
Definition: Lattice.cc:302
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
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.
Eigen::CwiseUnaryOp< decltype(Local::iround_l< typename Derived::Scalar >), const Derived > iround(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd to Eigen::MatrixXi.
const std::vector< Eigen::Matrix3i > & unimodular_matrices()
const SymOp::matrix_type & get_matrix(const SymOp &op)
Definition: SymOp.cc:167
GenericVectorXdScelFormatter lattice()
Definition: SupercellIO.cc:266
xtal::Coordinate copy_apply(const xtal::SymOp &op, xtal::Coordinate coord)
Copy and apply SymOp to a Coordinate.
Definition: Coordinate.cc:354
xtal::Coordinate & apply(const xtal::SymOp &op, xtal::Coordinate &coord)
apply SymOp to a Coordinate
Definition: Coordinate.cc:347
BasicStructure symmetrize(const BasicStructure &structure, const std::vector< SymOp > &enforced_group)
std::vector< Index > invariant_subgroup_indices(const Lattice &lat, SymOpVector const &super_grp)
Construct indices of the subgroup that leaves a lattice unchanged.
Eigen::Matrix3d const & get_matrix(MappingNode const &_node)
External accessor for isometry, to provide xtal::SymOp adaptability.
std::vector< SymOp > make_point_group(Lattice const &_lat)
Populate.
Definition: SymTools.cc:113
Main CASM namespace.
Definition: APICommand.hh:8
Eigen::Matrix3d Matrix3d
bool contains(const Container &container, const T &value)
Equivalent to container.end() != std::find(container.begin(), container.end(), value)
Definition: algorithm.hh:83
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
static SymOp point_operation(const SymOpMatrixType &mat)
Definition: SymType.hh:43