6 #include <unordered_set>
26 #include "casm/external/Eigen/Core"
27 #include "casm/external/Eigen/src/Core/Matrix.h"
31 #include "casm/external/Eigen/src/Core/PermutationMatrix.h"
32 #include "casm/external/Eigen/src/Core/util/Constants.h"
42 bool global_dofs_are_compatible_with_operation(
44 const std::map<DoFKey, xtal::DoFSet> &global_dof_map) {
45 for (
const auto &name_dof_pr : global_dof_map) {
58 int size = growing_point_group->size();
59 for (
int ix = 0; ix < size; ++ix) {
60 growing_point_group->emplace_back(growing_point_group->at(ix) *
70 std::pair<bool, xtal::Coordinate> map_translated_basis_and_calc_drift(
71 const std::vector<xtal::Site> &basis,
72 const std::vector<xtal::Site> &translatable_basis,
76 if (basis.size() != translatable_basis.size())
return {
false, drift};
78 for (
const xtal::Site &s_tb : translatable_basis) {
80 if (ix >= basis.size())
90 drift.
cart() /= double(basis.size());
95 void bring_within(std::vector<xtal::SymOp> *symmetry_group,
100 translation_coord.within();
101 operation.
translation = translation_coord.const_cart();
115 if (struc.
basis().size() == 0) {
121 for (
const xtal::SymOp &point_group_operation : point_group) {
124 if (!::global_dofs_are_compatible_with_operation(point_group_operation,
130 std::vector<xtal::Site> transformed_basis;
132 transformed_basis.emplace_back(point_group_operation *
s);
139 for (
const xtal::Site &transformed_site : transformed_basis) {
149 bool success =
false;
153 std::tie(success, drift) = map_translated_basis_and_calc_drift(
154 struc.
basis(), transformed_basis, translation, tol);
167 translation -= drift;
173 xtal::SymOp new_factor_group_operation(translation_operation *
174 point_group_operation);
176 equals_new_factor_group_operation(new_factor_group_operation,
180 equals_new_factor_group_operation) ==
193 xtal::close_group<xtal::SymOpPeriodicCompare_f>(&
factor_group,
204 make_factor_group_from_point_group(struc, identity_group,
false, tol);
205 return translation_group;
210 std::pair<xtal::BasicStructure, xtal::SymOpVector> make_primitive_factor_group(
220 ::expand_with_time_reversal(&primitive_point_group);
224 ::make_factor_group_from_point_group(primitive_struc,
225 primitive_point_group,
true, tol);
226 return std::make_pair(primitive_struc, primitive_factor_group);
235 for (
Index i = 0; i < basis.size(); i++) {
237 basis[i].min_dist(test_site) < tol) {
245 SymOpVector translation_group = ::make_translation_group(struc, tol);
247 return translation_group.size() == 1;
252 if (non_primitive_struc.
basis().size() == 0) {
253 return non_primitive_struc;
256 ::make_translation_group(non_primitive_struc, tol);
257 double minimum_possible_volume =
259 non_primitive_struc.
basis().size());
264 std::vector<Eigen::Vector3d> possible_lattice_vectors{
265 non_primitive_struc.
lattice()[0], non_primitive_struc.
lattice()[1],
266 non_primitive_struc.
lattice()[2]};
268 for (
const SymOp &trans_op : translation_group) {
270 possible_lattice_vectors.push_back(trans_op.translation);
276 double minimum_volume = std::abs(2 * non_primitive_struc.
lattice().
volume());
277 Eigen::Vector3d a_vector_primitive, b_vector_primitive, c_vector_primitive;
278 for (
const Eigen::Vector3d a_vector_candidate : possible_lattice_vectors) {
279 for (
const Eigen::Vector3d b_vector_candidate : possible_lattice_vectors) {
280 for (
const Eigen::Vector3d c_vector_candidate :
281 possible_lattice_vectors) {
283 a_vector_candidate, b_vector_candidate, c_vector_candidate));
284 if (possible_volume < minimum_volume &&
285 possible_volume > minimum_possible_volume) {
286 minimum_volume = possible_volume;
287 a_vector_primitive = a_vector_candidate;
288 b_vector_primitive = b_vector_candidate;
289 c_vector_primitive = c_vector_candidate;
294 Lattice non_reduced_form_primitive_lattice(
295 a_vector_primitive, b_vector_primitive, c_vector_primitive);
296 Lattice primitive_lattice =
niggli(non_reduced_form_primitive_lattice,
302 primitive_lattice, non_primitive_struc.
lattice());
307 for (
Site site_for_prim : non_primitive_struc.
basis()) {
308 site_for_prim.set_lattice(primitive_struc.
lattice(),
CART);
310 primitive_struc.
basis().size()) {
311 site_for_prim.within();
312 primitive_struc.
set_basis().emplace_back(std::move(site_for_prim));
318 return primitive_struc;
327 Eigen::Vector3d rotation_axis, _axis;
332 _axis = Eigen::Vector3d::Zero();
334 return std::make_pair(
angle, rotation_axis);
338 int det =
round(matrix.determinant());
342 Eigen::EigenSolver<Eigen::Matrix3d> t_eig(det * matrix);
345 for (
Index i = 0; i < 3; i++) {
346 if (
almost_equal(t_eig.eigenvalues()(i), std::complex<double>(1, 0))) {
347 _axis = t_eig.eigenvectors().col(i).real();
353 for (
Index i = 0; i < 3; i++) {
365 Eigen::Vector3d ortho = _axis.unitOrthogonal();
366 Eigen::Vector3d rot = det * (matrix * ortho);
368 (180. / M_PI) * atan2(_axis.dot(ortho.cross(rot)), ortho.dot(rot)) + 360.,
371 return std::make_pair(
angle, rotation_axis);
390 typedef Eigen::Matrix<double, 10, 1> key_type;
391 auto make_key = [](
const SymOp &op,
const Lattice &lat) {
395 Eigen::Vector3d sym_frac;
401 vec[offset] = -op.
matrix.determinant();
404 vec[offset] = -op.
matrix.trace();
407 vec[offset] = sym_angle;
410 vec.segment<3>(offset) = sym_frac;
420 auto op_compare = [tol](
const key_type &A,
const key_type &B) {
424 typedef std::map<key_type,
SymOp,
425 std::reference_wrapper<decltype(op_compare)>>
439 auto cclass_compare = [tol](
const map_type &A,
const map_type &B) {
446 std::set<map_type, std::reference_wrapper<decltype(cclass_compare)>> sorter(
450 map_type all_op(op_compare);
452 all_op.emplace(make_key(*it, lat), *it);
454 sorter.emplace(std::move(all_op));
458 for (
auto const &cclass : sorter) {
459 for (
auto it = cclass.begin(); it != cclass.end(); ++it) {
467 auto prim_factor_group_pair = ::make_primitive_factor_group(struc, tol);
468 const BasicStructure &primitive_struc = prim_factor_group_pair.first;
469 const std::vector<SymOp> &primitive_factor_group =
470 prim_factor_group_pair.second;
478 for (
const SymOp &prim_op : primitive_factor_group) {
484 if (std::find_if(point_group.begin(), point_group.end(),
485 equals_prim_op_ignoring_trans) == point_group.end()) {
491 for (
const UnitCell &lattice_point : all_lattice_points) {
522 std::vector<Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic, Index>>
525 std::string clr(100,
' ');
527 std::cout <<
"ERROR in xtal::make_permutation_representation" << std::endl;
528 std::cout <<
"Factor group is empty." << std::endl;
531 std::vector<xtal::UnitCellCoord> sitemap;
533 Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic, Index> init_perm_mat;
534 init_perm_mat.setIdentity(struc.
basis().size());
535 std::vector<Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic, Index>>
540 std::vector<Index> _perm(struc.
basis().size(), -1);
543 for (
Index b = 0; b < struc.
basis().size(); ++b) {
544 auto const &dofref_to =
545 struc.
basis()[sitemap[b].sublattice()].occupant_dof();
546 auto const &dofref_from = struc.
basis()[b].occupant_dof();
549 if (eq(op, dofref_to)) {
550 _perm[b] = sitemap[b].sublattice();
552 throw std::runtime_error(
553 "In Structure::_generate_basis_symreps(), Sites originally "
554 "identified as equivalent cannot be mapped by symmetry.");
556 Eigen::Map<Eigen::Matrix<Index, Eigen::Dynamic, 1>> index_matrix(
557 _perm.data(), _perm.size());
558 perm_rep[
s].indices() = index_matrix;
577 auto transformed_site_index = [&](
Site const &site,
SymOp const &op) {
578 Site transformed_site = op * site;
583 std::set<std::set<Index>> asym_unit;
585 std::set<Index> equivalent_sites;
587 equivalent_sites.insert(transformed_site_index(site, op));
589 asym_unit.insert(equivalent_sites);
610 const std::vector<SymOp> &enforced_group) {
619 decltype(avg_basis) operated_basis;
622 for (
const SymOp &enforce_group_operation : enforced_group) {
623 operated_basis.clear();
624 for (
const auto &symmetrized_structure_site :
625 symmetrized_structure.basis()) {
626 operated_basis.push_back(enforce_group_operation *
627 symmetrized_structure_site);
632 for (
Index b = 0; b < symmetrized_structure.basis().size(); b++) {
633 double smallest = 1000000;
634 Coordinate bshift(symmetrized_structure.lattice());
635 for (
const auto &operated_basis_site : operated_basis) {
637 operated_basis_site.min_dist(symmetrized_structure.basis()[b]);
638 if (dist < smallest) {
640 symmetrized_structure.basis()[b]);
644 bshift.
cart() *= (1.0 / enforced_group.size());
645 avg_basis[b] += bshift;
648 symmetrized_structure.set_basis(avg_basis);
649 return symmetrized_structure;
652 template <
typename IntegralType,
int Options>
655 const Eigen::Matrix<IntegralType, 3, 3, Options> &transformation_matrix) {
656 static_assert(std::is_integral<IntegralType>::value,
657 "Transfomration matrix must be integer matrix");
662 std::vector<UnitCell> all_lattice_points =
665 std::vector<Site> superstruc_basis;
666 for (
const Site &unit_basis_site : tiling_unit.
basis()) {
667 for (
const UnitCell &lattice_point : all_lattice_points) {
669 lattice_point, tiling_unit.
lattice(), superlat);
670 superstruc_basis.emplace_back(unit_basis_site + lattice_point_coordinate);
679 const Eigen::Matrix<int, 3, 3, 0> &transformation_matrix);
682 const Eigen::Matrix<long, 3, 3, 0> &transformation_matrix);
std::set< std::string > & s
Class for checking equivalence of two OccupantDoF objects, with respect to symmetry transformations.
BasicStructure specifies the lattice and atomic basis of a crystal.
std::map< DoFKey, DoFSet > const & global_dofs() const
std::vector< Site > & set_basis()
const std::string & title() const
void set_title(std::string const &_title)
Set the title of the structure.
const Lattice & lattice() const
bool is_time_reversal_active() const
Returns true if structure has attributes affected by time reversal.
const std::vector< Site > & basis() const
Represents cartesian and fractional coordinates.
Coordinate_impl::CartCoordinate cart()
Set Cartesian coordinate vector and update fractional coordinate vector.
const Lattice & lattice() const
Access the home lattice of the coordinate.
const vector_type & const_frac() const
user override to force const Access the fractional coordinate vector
Coordinate min_translation(const Coordinate &neighbor) const
Returns translation coordinate (in Angstr) to nearest periodic image of neighbor.
const vector_type & const_cart() const
user override to force const Access the Cartesian coordinate vector
double volume() const
Return signed volume of this lattice.
bool compare_type(const Site &test_site) const
const Lattice & prim_lattice() const
static Superlattice smooth_prim(const Lattice &tiling_unit, const Lattice &superlattice)
static UnitCellCoord from_coordinate(const PrimType &, const Coordinate &coord, double tol)
bool is_primitive(const Configuration &_config)
returns true if _config describes primitive cell of the configuration it describes
static Coordinate origin(const Lattice &_home)
construct a coordinate describing origin of _home lattice
Lattice make_superlattice(const Lattice &lat, const Eigen::Matrix< IntegralType, 3, 3, Options > &transf_mat)
Returns a super Lattice. Transformation matrix must be integer.
Derived::Scalar triple_product(const Derived &vec0, const Derived &vec1, const Derived &vec2)
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.
bool compare_type(AtomPosition const &A, AtomPosition const &B, double tol)
std::vector< UnitCellCoord > symop_site_map(SymOp const &_op, BasicStructure const &_struc)
To which site a SymOp transforms each basis site.
ConfigIO::GenericConfigFormatter< jsonParser > structure()
xtal::Coordinate copy_apply(const xtal::SymOp &op, xtal::Coordinate coord)
Copy and apply SymOp to a Coordinate.
std::set< std::set< Index > > make_asymmetric_unit(const xtal::BasicStructure &struc, const std::vector< SymOp > &factor_group)
Return indices of equivalent basis sites.
std::vector< UnitCell > make_lattice_points(const Eigen::Matrix3l &transformation_matrix)
template BasicStructure make_superstructure< long, 0 >(const BasicStructure &tiling_unit, const Eigen::Matrix< long, 3, 3, 0 > &transformation_matrix)
BasicStructure symmetrize(const BasicStructure &structure, const std::vector< SymOp > &enforced_group)
std::vector< SymOp > make_factor_group(const BasicStructure &struc, double tol=TOL)
std::vector< Eigen::PermutationMatrix< Eigen::Dynamic, Eigen::Dynamic, Index > > make_permutation_representation(const xtal::BasicStructure &struc, const std::vector< SymOp > &factor_group)
Create the permutation group of a structure.
void sort_factor_group(std::vector< SymOp > &factor_group, const Lattice &lat)
Sort SymOp in the SymGroup.
std::pair< double, Eigen::Vector3d > calc_rotation_angle_and_axis(const SymOp &op, const Lattice &lat)
Calculates the rotation angle and axis of a symmetry operation. This function is almost exactly ident...
BasicStructure make_primitive(const BasicStructure &non_primitive_struc, double tol=TOL)
Returns the smallest possible tiling unit of the given structure.
bool is_primitive(const BasicStructure &struc, double tol=TOL)
Coordinate make_superlattice_coordinate(const UnitCell &ijk, const Superlattice &superlattice)
Lattice niggli(const Lattice &in_lat, double compare_tol, bool keep_handedness=false)
template BasicStructure make_superstructure< int, 0 >(const BasicStructure &tiling_unit, const Eigen::Matrix< int, 3, 3, 0 > &transformation_matrix)
Index find_index(const std::vector< Site > &basis, const Site &test_site, double tol)
BasicStructure make_superstructure(const BasicStructure &tiling_unit, const Eigen::Matrix< IntegralType, 3, 3, Options > &transformation_matrix)
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.
void swap(ConfigDoF &A, ConfigDoF &B)
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
int float_sgn(T val, double compare_tol=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.
INDEX_TYPE Index
For long integer indexing:
static SymOp translation_operation(const SymOpTranslationType &translation)
SymOpTranslationType translation
SymOpTimeReversalType is_time_reversal_active
static SymOp time_reversal()