4 #include "casm/external/Eigen/Dense"
31 Eigen::Matrix3i generating_matrix;
33 generating_matrix = Eigen::Matrix3i::Identity();
35 else if(input[
"unit_cell"].is_array()) {
36 from_json(generating_matrix, input[
"unit_cell"]);
38 else if(input[
"unit_cell"].is_string()) {
42 throw std::invalid_argument(
43 "Error reading unit cell from JSON input: 'unit_cell' must be a 3x3 integer matrix or supercell name");
45 return generating_matrix;
81 throw std::invalid_argument(
82 "Error in ScelEnumProps JSON input: 'min_volume' must be >0");
88 if(scel.volume() > max_scel_size) {
89 max_scel_size = scel.volume();
93 input.
get_else(max_vol,
"max", max_scel_size);
94 if(!(max_vol >= min_vol)) {
95 throw std::invalid_argument(
96 "Error in ScelEnumProps JSON input: 'max' must be greater than or equal to 'min'");
100 Eigen::Matrix3i generating_matrix =
make_unit_cell(primclex, input);
103 input.
get_else<std::string>(dirs,
"dirs",
"abc");
105 return ScelEnumProps(min_vol, max_vol + 1, dirs, generating_matrix);
189 throw std::runtime_error(
"Determinants of Hermite normal form matrices must be greater than 0");
201 namespace HermiteCounter_impl {
204 assert(attempt <= diag(position));
205 assert(position < diag.size() - 1);
206 assert(diag(position + 1) == 1);
207 assert(diag(position) > 1);
208 assert(attempt >= 2);
213 while(diag(position) % attempt != 0) {
217 diag(position) = diag(position) / attempt;
218 diag(position + 1) = attempt;
230 if(position == diag.size() - 1) {
234 while(position >= 0 && diag(position) == 1);
243 attempt = diag(diag.size() - 1) + 1;
244 diag(position) = diag(position) * diag(diag.size() - 1);
245 diag(diag.size() - 1) = 1;
252 assert(init_dim > 0);
256 for(
int i = 0; i < init_dim; i++) {
268 Eigen::VectorXi begincount(Eigen::VectorXi::Zero(uppersize));
271 Eigen::VectorXi stepcount(Eigen::VectorXi::Ones(uppersize));
274 Eigen::VectorXi endcount(Eigen::VectorXi::Zero(uppersize));
279 endcount(slot) = current_diag(i) - 1;
287 Eigen::MatrixXi
_zip_matrix(
const Eigen::VectorXi ¤t_diag,
const Eigen::VectorXi ¤t_upper_tri) {
288 assert(current_upper_tri.size() ==
upper_size(current_diag.size()));
290 Eigen::MatrixXi hmat(current_diag.asDiagonal());
293 for(
Index i = 0; i < current_diag.size() - 1; i++) {
294 for(
Index j = i + 1; j < current_diag.size(); j++) {
295 hmat(i, j) = current_upper_tri(slot);
325 Eigen::MatrixXi
_expand_dims_old(
const Eigen::MatrixXi &hermit_mat,
const Eigen::VectorXi &active_dims) {
326 assert(hermit_mat.rows() == active_dims.sum() && hermit_mat.cols() == active_dims.sum());
327 assert(active_dims.maxCoeff() == 1 && active_dims.minCoeff() == 0);
329 Eigen::MatrixXi expanded(Eigen::MatrixXi::Identity(active_dims.size(), active_dims.size()));
335 for(i = 0; i < expanded.rows(); i++) {
336 if(active_dims(i) == 0) {
345 for(j = 0; j < expanded.cols(); j++) {
346 if(active_dims(j) == 0) {
354 expanded(i, j) = hermit_mat(si, sj);
407 Eigen::MatrixXi
_expand_dims(
const Eigen::MatrixXi &H,
const Eigen::MatrixXi &G) {
408 assert(H.rows() == H.cols());
409 assert(G.rows() == G.cols());
410 assert(G.rows() >= H.rows());
416 Eigen::MatrixXi B(m, m);
417 Eigen::MatrixXi I_block(Eigen::MatrixXi::Identity(m - n, m - n));
418 Eigen::MatrixXi Z_block(Eigen::MatrixXi::Zero(n, m - n));
419 B << H, Z_block, Z_block.transpose(), I_block;
444 assert(hermit_mat.rows() == hermit_mat.cols());
446 int dims = hermit_mat.rows();
449 for(
int i = dims; i > 0; i--) {
453 Eigen::VectorXi unrolled_herm(unrolldim);
458 enum STEP {DOWN, UP, LEFT};
459 STEP curr_step = DOWN;
461 Index unroll_ind = 0;
463 for(
Index i = 0; i < dims; i++) {
464 for(
Index j = 0; j < dims - i; j++) {
478 unrolled_herm(unroll_ind) = hermit_mat(lasti, lastj);
495 return unrolled_herm;
522 assert(unrolled_H0.size() == unrolled_H1.size());
524 for(
Index i = 0; i < unrolled_H0.size(); i++) {
525 if(unrolled_H0(i) > unrolled_H1(i)) {
529 else if(unrolled_H0(i) < unrolled_H1(i)) {
549 m_begin_volume(enum_props.begin_volume()),
550 m_end_volume(enum_props.end_volume()),
551 m_gen_mat(enum_props.generating_matrix()),
552 m_dims(enum_props.dims()) {
555 throw std::runtime_error(
"The transformation matrix to expand into a 3x3 matrix must have a positive determinant!");
568 m_point_group(point_grp),
569 m_begin_volume(enum_props.begin_volume()),
570 m_end_volume(enum_props.end_volume()),
571 m_gen_mat(enum_props.generating_matrix()),
572 m_dims(enum_props.dims()) {
575 throw std::runtime_error(
"The transformation matrix to expand into a 3x3 matrix must have a positive determinant!");
584 const Eigen::Matrix3i &T,
590 auto init_vol = T.determinant();
592 while(m * m * m * init_vol < volume) {
596 return m * Eigen::Matrix3i::Identity();
599 auto init_vol = T.determinant();
601 while(m * init_vol < volume) {
605 auto compactness = [](
const Lattice & lat) {
607 return (L.transpose() * L).trace();
611 return compactness(A) < compactness(B);
616 return best_it.matrix();
661 Eigen::Matrix3i H_best;
664 for(
Index i = 0; i < effective_pg.
size(); i++) {
665 Eigen::Matrix3i transformed =
iround(lat.inverse() * effective_pg[i].matrix() * lat) * H;
670 H_best = H_transformed;
Index _increment_diagonal()
Go to the next values of diagonal elements that keep the same determinant.
HermiteCounter::Index _spill_factor(Eigen::VectorXi &diag, HermiteCounter::Index position, HermiteCounter::value_type attempt)
Find the next factor of the specified position and share with next element. Use attempt as starting p...
value_type determinant() const
Get the current determinant.
const Container & current() const
boost::container::stable_vector< Supercell > & get_supercell_list()
Access entire supercell_list.
Lattice m_lat
The lattice of the unit cell.
Eigen::MatrixXi _expand_dims(const Eigen::MatrixXi &H, const Eigen::MatrixXi &G)
Expand a n x n Hermite normal matrix (H) into a m x m one through a m x m generating matrix (G) (e...
void from_json(ClexDescription &desc, const jsonParser &json)
A Counter allows looping over many incrementing variables in one loop.
Eigen::VectorXi diagonal() const
void generate_point_group(SymGroup &point_group, double pg_tol=TOL) const
Populate.
bool compare(const T &A, const T &B, double tol)
Floating point comparison with tol, return A < B.
Data structure for holding supercell enumeration properties.
Eigen::Matrix3i canonical_hnf(const Eigen::Matrix3i &T, const SymGroup &effective_pg, const Lattice &ref_lattice)
Return canonical hermite normal form of the supercell matrix, and op used to find it...
Index m_pos
Keeps track of the current diagonal element that needs to be factored.
bool _canonical_compare(const Eigen::MatrixXi &H0, const Eigen::MatrixXi &H1)
Compare two integer matrices and see which one is lexicographically greatest. Returns true if H0
Eigen::MatrixXi _zip_matrix(const Eigen::VectorXi ¤t_diag, const Eigen::VectorXi ¤t_upper_tri)
Assemble a matrix diagonal and unrolled upper triangle values into a matrix.
const_iterator end() const
A const iterator to the past-the-last volume.
Eigen::MatrixXi _expand_dims_old(const Eigen::MatrixXi &hermit_mat, const Eigen::VectorXi &active_dims)
Expand a n x n Hermite normal matrix into a m x m one (e.g. for 2D supercells)
A fake container of supercell matrices.
void jump_to_determinant(value_type new_det)
Reset the diagonal to the specified determinant and set the other elements to zero.
Eigen::Matrix3i enforce_min_volume< Lattice >(const Lattice &unit, const Eigen::Matrix3i &T, const SymGroup &point_grp, Index volume, bool fix_shape)
const Eigen::Matrix3d & lat_column_mat() const
3x3 matrix with lattice vectors as its columne
Index dim() const
Get the dimensions of *this.
Eigen::MatrixXi operator()() const
Get the current matrix the counter is on.
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
EigenCounter< Eigen::VectorXi > EigenVectorXiCounter
Counter for Eigen::VectorXi.
const_iterator begin() const
A const iterator to the beginning volume, specify here how the iterator should jump through the enume...
bool is_null() const
Check if null type.
Eigen::VectorXi _canonical_unroll(const Eigen::MatrixXi &hermit_mat)
Unroll a Hermit normal form square matrix into a vector such that it's canonical form is easy to comp...
ScelEnumProps make_scel_enum_props(PrimClex &primclex, const jsonParser &input)
Make a ScelEnumProps object from JSON input.
SymGroup m_point_group
The point group of the unit cell.
EigenIndex Index
For long integer indexing:
HermiteCounter & operator++()
Jump to the next available HNF matrix.
bool get_else(T &t, const std::string &key, const T &default_value, Args...args) const
PrimClex is the top-level data structure for a CASM project.
HermiteCounter(int init_determinant, int init_dim)
constructor to satisfy iterator requirements. Do not recommend.
std::pair< Eigen::MatrixXi, Eigen::MatrixXi > hermite_normal_form(const Eigen::MatrixXi &M)
Return the hermite normal form, M == H*V.
EigenVectorXiCounter m_upper_tri
unrolled vector of the upper triangle (does not include diagonal elements)
void reset_current()
reset the counter to the first iteration of the current determinant
void next_determinant()
Skip the remaining iterations and start at the next determinant value.
Eigen::VectorXi m_diagonal
Vector holding diagonal element values.
const Supercell & get_supercell(Index i) const
const Access supercell by index
bool contains(const std::string &name) const
Return true if JSON object contains 'name'.
HermiteCounter::Index upper_size(HermiteCounter::Index init_dim)
Determine the number of elements in the upper triangular matrix (excluding diagonal) ...
double volume(const Lattice &lat)
Returns the volume of a Lattice.
Eigen::CwiseUnaryOp< decltype(std::ptr_fun(boost::math::iround< typename Derived::Scalar >)), const Derived > iround(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd to Eigen::MatrixXi.
HermiteCounter::Index next_spill_position(Eigen::VectorXi &diag, HermiteCounter::Index position)
Spill the next factor of the specified element with its neighbor, and return new position.
const Eigen::Matrix3i & get_transf_mat() const
EigenVectorXiCounter _upper_tri_counter(const Eigen::VectorXi ¤t_diag)
Create a counter for the elements above the diagonal based on the current diagonal value...
Eigen::VectorXi::Scalar value_type
const Eigen::Matrix3i m_gen_mat
This matrix (G) specifies new lattice vectors to enumerate over column-wise, such that the resulting ...
Eigen::MatrixXi current() const
Get the current matrix the counter is on.
SupercellEnumerator(UnitType unit, const ScelEnumProps &enum_props, double tol)
Construct a SupercellEnumerator.
Eigen::Matrix3i make_unit_cell(PrimClex &primclex, const jsonParser &json)
Read unit cell transformation matrix from JSON input.