13 Eigen::Ref<const Eigen::Vector3d>
const &vec2,
14 Eigen::Ref<const Eigen::Vector3d>
const &vec3,
double xtal_tol,
18 if (!force &&
m_lat_mat.determinant() < 0) {
31 for (i = 0; i < 3; i++) {
32 for (j = 0; j < 3; j++) {
36 skew[l + 12](i, j) = -1;
43 for (i = 0; i < 3; i++) {
52 skew[l + 12](j, i) = -1;
53 skew[l + 12](k, i) = -1;
60 skew[l + 12](j, i) = -1;
61 skew[l + 12](k, i) = 1;
77 double xtal_tol,
bool force)
78 : m_lat_mat(lat_mat), m_inv_lat_mat(lat_mat.
inverse()), m_tol(xtal_tol) {
79 if (!force &&
m_lat_mat.determinant() < 0) {
93 latmat /= pow(latmat.determinant(), 1.0 / 3.0);
104 latmat /= pow(latmat.determinant(), 1.0 / 3.0);
115 latmat << 1, -1.0 / sqrt(3.0),
116 0, 0, 2.0 / sqrt(3.0),
148 int tprec = stream.precision();
149 std::ios::fmtflags tflags = stream.flags();
150 stream.precision(_prec);
151 stream.flags(std::ios::showpoint | std::ios::fixed | std::ios::right);
152 Eigen::IOFormat format(_prec);
154 stream << 1.0 <<
'\n';
155 stream <<
m_lat_mat.transpose().format(format);
157 stream.precision(tprec);
158 stream.flags(tflags);
172 std::vector<int> super_kpoints = prim_kpoints;
176 double prim_density = (prim_kpoints[0] * prim_kpoints[1] * prim_kpoints[2]) / (prim_recip_lat.
volume());
177 double super_density = 0;
179 std::vector<double> prim_vec_lengths;
181 for(
int i = 0; i < 3; i++) {
182 prim_vec_lengths.push_back(prim_recip_lat.
length(i));
185 double shortest = *std::min_element(prim_vec_lengths.begin(), prim_vec_lengths.end());
186 int short_ind =
find_index(prim_vec_lengths, shortest);
188 double scale = (prim_kpoints[short_ind] / shortest);
190 for(
int i = 0; i < 3; i++) {
191 super_kpoints[i] = int(ceil(scale * recip_lat.
length(i)));
194 super_density = (super_kpoints[0] * super_kpoints[1] * super_kpoints[2]) / (recip_lat.
volume());
196 while(super_density < prim_density) {
197 prim_kpoints[short_ind]++;
199 scale = (prim_kpoints[short_ind] / shortest);
201 for(
int i = 0; i < 3; i++) {
202 super_kpoints[i] = int(ceil(scale * recip_lat.
length(i)));
205 super_density = (super_kpoints[0] * super_kpoints[1] * super_kpoints[2]) / (recip_lat.
volume());
208 return super_kpoints;
239 reduced_imetric = reduced_metric.inverse();
241 bool minimized =
false;
244 for(
Index i = 0; i < skew.size(); ++i) {
246 t_metric = skew[i].transpose() * reduced_metric * skew[i];
247 t_imetric = skew[(i + 12) % 12].transpose() * reduced_imetric * skew[(i + 12) % 12];
256 reduced_metric = t_metric;
257 reduced_imetric = t_imetric;
262 else if(t_imetric.trace() < reduced_imetric.trace()) {
263 reduced_metric = t_metric;
264 reduced_imetric = t_imetric;
269 else if(t_metric.trace() < reduced_metric.trace()) {
270 reduced_metric = t_metric;
271 reduced_imetric = t_imetric;
278 for(
Index i = 0; i < ntrans.size(); ++i) {
280 if(tb_index > b_index) {
282 reduced_metric = ntrans[i].transpose() * reduced_metric * ntrans[i];
283 reduced_imetric = reduced_metric.inverse();
304 bool right_handed = (reduced_lat.determinant() > 0);
305 Eigen::HouseholderQR<Eigen::Matrix3d> qr(reduced_lat);
309 ortho.col(0) = ortho.col(0) * R(0, 0);
310 ortho.col(1) = ortho.col(1) * R(1, 1);
311 ortho.col(2) = ortho.col(2) * R(2, 2);
314 for(
int j = k - 1; j >= 0; j--) {
315 double mu = reduced_lat.col(k).dot(ortho.col(j)) / ortho.col(j).squaredNorm();
316 if(fabs(mu) > 0.5000001) {
317 reduced_lat.col(k) = reduced_lat.col(k) -
round(mu) * reduced_lat.col(j);
318 Eigen::HouseholderQR<Eigen::Matrix3d> qr2(reduced_lat);
319 Q = qr2.householderQ();
320 R = Q.inverse() * reduced_lat;
322 ortho.col(0) = ortho.col(0) * R(0, 0);
323 ortho.col(1) = ortho.col(1) * R(1, 1);
324 ortho.col(2) = ortho.col(2) * R(2, 2);
327 double mu2 = reduced_lat.col(k).dot(ortho.col(k - 1)) / ortho.col(k - 1).squaredNorm();
328 if((ortho.col(k) + mu2 * ortho.col(k - 1)).squaredNorm() > (0.75) * ortho.col(k - 1).squaredNorm()) {
332 Eigen::Vector3d tmp = reduced_lat.col(k);
333 reduced_lat.col(k) = reduced_lat.col(k - 1);
334 reduced_lat.col(k - 1) = tmp;
335 Eigen::HouseholderQR<Eigen::Matrix3d> qr3(reduced_lat);
336 Q = qr3.householderQ();
337 R = Q.inverse() * reduced_lat;
339 ortho.col(0) = ortho.col(0) * R(0, 0);
340 ortho.col(1) = ortho.col(1) * R(1, 1);
341 ortho.col(2) = ortho.col(2) * R(2, 2);
348 return Lattice(reduced_lat).make_right_handed();
369 for(
Index nv = 0; nv < vtable.rows(); nv++) {
370 tproj = vtable.row(nv) * pos;
374 else if(tproj > 1.0) {
388 Eigen::Vector3d tpoint;
398 for(; combo_count.
valid(); ++combo_count) {
399 if(combo_count().isZero())
403 for(i = 0; i < 3; i++) {
404 if(combo_count[(i + 1) % 3] == 0 || combo_count[(i + 2) % 3] == 0)
406 if((180. / M_PI) *
CASM::angle(combo_count[(i + 1) % 3] * tlat_reduced[(i + 1) % 3],
407 combo_count[(i + 2) % 3] * tlat_reduced[(i + 2) % 3]) +
418 tpoint = tlat_reduced.
lat_column_mat() * combo_count().cast<
double>();
420 double t_rad = tpoint.norm();
449 for(
int i = 0; i < 3; i++) {
450 recip.col(i) *= radius / recip.col(i).norm();
453 auto lambda = [](
double val) {
456 return (
inv_lat_column_mat() * recip).cwiseAbs().unaryExpr(lambda).colwise().maxCoeff().cast<
int>();
504 if(
millers == Eigen::Vector3i(0, 1, 0)) {
508 else if(
millers == Eigen::Vector3i(1, 0, 0)) {
512 else if(
millers == Eigen::Vector3i(0, 0, 1)) {
536 Eigen::Vector3d H_miller_point, K_miller_point;
538 Eigen::Vector3d millers_dubs;
541 millers_dubs =
millers.cast<
double>();
543 Eigen::Vector3d inv_miller_dubs;
544 Eigen::Vector3i inv_miller;
548 inv_miller_dubs[zero] = 0;
549 inv_miller_dubs[(zero + 1) % 3] = 1.0 / millers_dubs[(zero + 1) % 3];
550 inv_miller_dubs[(zero + 2) % 3] = 1.0 / millers_dubs[(zero + 2) % 3];
553 H_miller_point = inv_miller[(zero + 1) % 3] *
lat_column_mat().col((zero + 1) % 3);
554 K_miller_point = inv_miller[(zero + 2) % 3] *
lat_column_mat().col((zero + 2) % 3);
556 HK = K_miller_point - H_miller_point;
557 surface_cell.col(1) = HK;
564 Eigen::Vector3d H_miller_point, K_miller_point, L_miller_point;
565 Eigen::Vector3d inv_miller_dubs;
566 Eigen::Vector3i inv_miller;
568 Eigen::Vector3d millers_dubs;
569 millers_dubs =
millers.cast<
double>();
571 inv_miller_dubs[0] = 1.0 / millers_dubs[0];
572 inv_miller_dubs[1] = 1.0 / millers_dubs[1];
573 inv_miller_dubs[2] = 1.0 / millers_dubs[2];
584 Eigen::Vector3d HK, KL, LH;
585 Eigen::Vector3d tangles;
587 HK = K_miller_point - H_miller_point;
588 KL = L_miller_point - K_miller_point;
589 LH = H_miller_point - L_miller_point;
600 for(
int i = 1; i < 3; i++) {
608 for(
int i = 0; i < 3; i++) {
610 for(
int j = maxval; j > 1; j--) {
614 for(
int k = 0; k < 3; k++) {
634 double HKKL, KLLH, LHHK;
635 HKKL = HK.cross(KL).norm();
636 KLLH = KL.cross(LH).norm();
637 LHHK = LH.cross(HK).norm();
639 if(HKKL <= KLLH && HKKL <= LHHK) {
640 surface_cell.col(0) = HK;
641 surface_cell.col(1) = KL;
644 else if(KLLH <= HKKL && KLLH <= LHHK) {
645 surface_cell.col(0) = KL;
646 surface_cell.col(1) = LH;
650 surface_cell.col(0) = LH;
651 surface_cell.col(1) = HK;
658 Eigen::Vector3d normal;
659 Eigen::Vector3i L_combination;
668 if(fabs(normal[0]) >= fabs(normal[1]) && fabs(normal[0]) >= fabs(normal[2]) && normal[0] != 0) {
669 normal = normal / normal[0];
672 else if(fabs(normal[1]) >= fabs(normal[2]) && fabs(normal[1]) >= fabs(normal[0]) && fabs(normal[1]) != 0) {
673 normal = normal / normal[1];
677 normal = normal / normal[2];
680 Eigen::Vector3d tnormal;
682 double orthoscore = 1;
683 double torthoscore = 0;
688 bool one_found =
false;
691 normal = tnormal * factor;
694 L_combination[0] = int(floor(normal[0] + 0.5));
695 L_combination[1] = int(floor(normal[1] + 0.5));
696 L_combination[2] = int(floor(normal[2] + 0.5));
700 surface_cell.col(2) =
lat_column_mat() * L_combination.cast<
double>();
703 if(orthoscore > torthoscore +
TOL) {
704 torthoscore = orthoscore;
706 last_surface_cell = surface_cell;
709 new_vol = fabs(surface_cell.col(2).dot(surface_cell.col(0).cross(surface_cell.col(1))));
716 throw std::runtime_error(
"failed get_lattice_in_plane");
718 std::cerr <<
"Reached an outrageous size. Returning last generated cell" << std::endl;
719 surface_cell = last_surface_cell;
724 while(new_vol / this->
volume() < max_vol && orthoscore < 1);
726 Lattice surface_lat(surface_cell.col(0), surface_cell.col(1), surface_cell.col(2));
739 if(A_is_niggli != B_is_niggli) {
786 long N = 1, num, denom;
787 for(
Index i = 0; i < 3; i++) {
788 for(
Index j = 0; j < 3; j++) {
801 for(
Index i = 0; i < 3; i++) {
802 S(i, i) = N /
gcf(S(i, i), N);
816 double min_vol = std::abs(
volume(new_lat));
818 for(
int i = 0; i < 3; i++) {
821 tmp_lat[i] = new_vector;
822 double vol = std::abs(
volume(tmp_lat));
824 if(vol < min_vol && vol > tol) {
842 result.first =
almost_zero((diff.transpose() * diff).diagonal().eval(), 2 * tol) && !
almost_zero(result.second, tol);
851 bool is_integer_transformation;
854 std::tie(is_integer_transformation, transformation_matrix) =
is_superlattice(superlattice, tiling_unit, tol);
856 if(!is_integer_transformation) {
857 throw std::runtime_error(
"The provided tiling unit and superlattice are not related by a non-singular integer transformation.");
860 return lround(transformation_matrix);
std::set< std::string > & s
A Counter allows looping over many incrementing variables in one loop.
bool is_right_handed() const
Check if the lattice is right handed.
Eigen::Matrix3d m_inv_lat_mat
void print(std::ostream &stream, int _prec=8) const
int voronoi_number(const Eigen::Vector3d &pos) const
Eigen::Vector3i millers(Eigen::Vector3d plane_normal) const
std::vector< int > calc_kpoints(std::vector< int > prim_kpoints, Lattice prim_lat)
double length(Index i) const
Return length of i'th lattice vector.
const Eigen::Matrix3d & lat_column_mat() const
3x3 matrix with lattice vectors as its columne
double m_inner_voronoi_radius
Eigen::Vector3i enclose_sphere(double radius) const
double max_voronoi_measure(const Eigen::Vector3d &pos, Eigen::Vector3d &lattice_trans) const
Lattice(Eigen::Ref< const Eigen::Vector3d > const &vec1, Eigen::Ref< const Eigen::Vector3d > const &vec2, Eigen::Ref< const Eigen::Vector3d > const &vec3, double xtal_tol=TOL, bool force=false)
static Lattice bcc(double tol=TOL)
Construct BCC primitive cell of unit volume.
Lattice lattice_in_plane(Eigen::Vector3i millers, int max_vol=0) const
bool _eq(const Lattice &RHS) const
Are lattice vectors identical for two lattices, within TOL.
double boxiness() const
Return boxiness factor directly proportional to volume/SA ratio.
Lattice reduced_cell2() const
Find the lattice vectors which give most compact unit cell Compactness is measured by how close lat_c...
Lattice reduced_cell() const
Find the lattice vectors which give most compact unit cell Compactness is measured by how close lat_c...
Eigen::MatrixXd m_voronoi_table
Lattice scaled_lattice(double scale) const
Return scaled copy of this lattice (Note: Volume will be scaled by scale^3)
double angle(Index i) const
Return angle between lattice vectors (*this)[(i+1)%3] and (*this)[(i+2)%3], in degrees.
static std::vector< Eigen::Matrix3d > const & skew_transforms()
double volume() const
Return signed volume of this lattice.
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...
bool operator<(const Lattice &RHS) const
Compare two Lattice.
static Lattice cubic(double tol=TOL)
Construct simple cubic primitive cell of unit volume.
static Lattice hexagonal(double tol=TOL)
Construct cubic primitive cell of unit volume.
Eigen::Matrix3d m_lat_mat
Eigen::MatrixXd const & voronoi_table() const
Return voronoi table, which specifies outward-pointing normals of Lattice Voronoi cell....
Lattice & make_right_handed()
Flip c vector if it's on the wrong side of a-b plane – return (*this)
Lattice reciprocal() const
Return reciprocal lattice.
static Lattice fcc(double tol=TOL)
Construct FCC primitive cell of unit volume.
void _generate_voronoi_table() const
populate voronoi information.
void read(std::istream &stream)
static std::vector< Eigen::Matrix3d > const & cell_invariant_transforms()
double volume(const Lattice &lat)
Returns the volume of a Lattice.
std::pair< bool, Eigen::Matrix3d > is_superlattice(const Lattice &scel, const Lattice &unit, double tol)
Check if scel is a superlattice of unitcell unit and some integer transformation matrix T.
Lattice make_superduperlattice(const Lattice &lat1, const Lattice &lat2)
returns Lattice that is smallest possible superlattice of both input Lattice
void smith_normal_form(const Eigen::MatrixBase< DerivedIn > &M, Eigen::MatrixBase< DerivedOut > &U, Eigen::MatrixBase< DerivedOut > &S, Eigen::MatrixBase< DerivedOut > &V)
Return the smith normal form, M == U*S*V.
Eigen::CwiseUnaryOp< decltype(Local::lround_l< typename Derived::Scalar >), const Derived > lround(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd to Eigen::MatrixXl.
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.
T norm(const Tensor< T > &ttens)
IdentitySymRepBuilder Identity()
Index niggli_index(const Eigen::Matrix3d &test_lat_mat, double compare_tol)
Number of niggli criteria met.
Eigen::Matrix3l make_transformation_matrix_to_super(const Lattice &tiling_unit, const Lattice &superlattice, double tol)
bool is_niggli(const Eigen::Matrix3d &test_lat_mat, double compare_tol)
std::vector< Eigen::Matrix3d > _skew_transforms()
Lattice replace_vector(const Lattice &lat, const Eigen::Vector3d &new_vector, double tol)
Index find_index(const std::vector< Site > &basis, const Site &test_site, double tol)
bool standard_orientation_compare(const Eigen::Matrix3d &low_score_lat_mat, const Eigen::Matrix3d &high_score_lat_mat, double compare_tol)
Determine whether high_score has a more standard format than low_score.
bool almost_equal(ClusterInvariants const &A, ClusterInvariants const &B, double tol)
Check if ClusterInvariants are equal.
void nearest_rational_number(double val, long &numerator, long &denominator, double tol=TOL)
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
INDEX_TYPE Index
For long integer indexing:
int gcf(int i1, int i2)
Find greatest common factor.
Matrix< long int, 3, 3 > Matrix3l
Eigen::Matrix< int, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > scale_to_int(const Eigen::MatrixBase< Derived > &val, double _tol=CASM::TOL)