CASM  1.1.0
A Clusters Approach to Statistical Mechanics
Supercell.cc
Go to the documentation of this file.
1 #include <boost/filesystem.hpp>
2 #include <boost/filesystem/fstream.hpp>
3 #include <boost/lexical_cast.hpp>
4 #include <vector>
5 
6 #include "casm/basis_set/DoF.hh"
7 #include "casm/casm_io/Log.hh"
11 #include "casm/clex/PrimClex.hh"
22 #include "casm/global/errors.hh"
23 
24 namespace CASM {
25 
26 template class SupercellCanonicalForm<CRTPBase<Supercell> >;
27 template class HasPrimClex<
28  DB::Named<Comparisons<SupercellCanonicalForm<CRTPBase<Supercell> > > > >;
29 
30 namespace DB {
31 template class DB::Named<
32  Comparisons<SupercellCanonicalForm<CRTPBase<Supercell> > > >;
33 }
34 
35 // Copy constructor is needed for proper initialization of supercell sym info
37  : m_primclex(RHS.m_primclex),
38  m_shared_prim(RHS.m_shared_prim),
39  m_sym_info(make_supercell_sym_info(prim(), RHS.lattice())),
40  m_nlist_size_at_construction(-1) {}
41 
42 Supercell::Supercell(std::shared_ptr<Structure const> const &_shared_prim,
43  Eigen::Matrix3l const &transf_mat_init)
44  : m_primclex(nullptr),
45  m_shared_prim(_shared_prim),
46  m_sym_info(make_supercell_sym_info(
47  prim(), Lattice(prim().lattice().lat_column_mat() *
48  transf_mat_init.cast<double>(),
49  crystallography_tol()))),
50  m_nlist_size_at_construction(-1) {}
51 
52 Supercell::Supercell(std::shared_ptr<Structure const> const &_shared_prim,
53  const Lattice &superlattice)
54  : m_primclex(nullptr),
55  m_shared_prim(_shared_prim),
56  m_sym_info(make_supercell_sym_info(prim(), superlattice)),
57  m_nlist_size_at_construction(-1) {
58  auto res = xtal::is_superlattice(superlattice, prim().lattice(),
60  if (!res.first) {
61  err_log()
62  << "Error in Supercell(PrimClex *_prim, const Lattice &superlattice)"
63  << std::endl
64  << " Bad supercell, the transformation matrix is not integer."
65  << std::endl;
66  err_log() << "superlattice: \n"
67  << superlattice.lat_column_mat() << std::endl;
68  err_log() << "prim lattice: \n"
69  << prim().lattice().lat_column_mat() << std::endl;
70  err_log() << "transformation matrix: \n" << res.second << std::endl;
71  throw std::invalid_argument(
72  "Error constructing Supercell: the transformation matrix is not "
73  "integer");
74  }
75 }
76 
78  const Eigen::Ref<const Eigen::Matrix3l> &transf_mat_init)
79  : m_primclex(_prim),
80  m_shared_prim(_prim->shared_prim()),
81  m_sym_info(make_supercell_sym_info(
82  prim(), Lattice(prim().lattice().lat_column_mat() *
83  transf_mat_init.cast<double>(),
84  crystallography_tol()))),
85  m_nlist_size_at_construction(-1) {}
86 
87 Supercell::Supercell(const PrimClex *_prim, const Lattice &superlattice)
88  : m_primclex(_prim),
89  m_shared_prim(_prim->shared_prim()),
90  m_sym_info(make_supercell_sym_info(prim(), superlattice)),
91  m_nlist_size_at_construction(-1) {
92  auto res = xtal::is_superlattice(superlattice, prim().lattice(),
94  if (!res.first) {
95  err_log()
96  << "Error in Supercell(PrimClex *_prim, const Lattice &superlattice)"
97  << std::endl
98  << " Bad supercell, the transformation matrix is not integer."
99  << std::endl;
100  err_log() << "superlattice: \n"
101  << superlattice.lat_column_mat() << std::endl;
102  err_log() << "prim lattice: \n"
103  << prim().lattice().lat_column_mat() << std::endl;
104  err_log() << "transformation matrix: \n" << res.second << std::endl;
105  throw std::invalid_argument(
106  "Error constructing Supercell: the transformation matrix is not "
107  "integer");
108  }
109 }
110 
112 
113 const Structure &Supercell::prim() const { return *shared_prim(); }
114 
115 std::shared_ptr<Structure const> const &Supercell::shared_prim() const {
116  return m_shared_prim;
117 }
118 
119 double Supercell::crystallography_tol() const { return prim().lattice().tol(); }
120 
127 bool Supercell::has_primclex() const { return m_primclex != nullptr; }
128 
135 // - The m_primclex pointer is mutable as a temporary workaround
136 void Supercell::set_primclex(PrimClex const *_primclex) const {
137  if (m_primclex != nullptr && m_primclex != _primclex) {
138  throw std::runtime_error(
139  "Error in Supercell::set_primclex: primclex should not change");
140  }
141  m_primclex = _primclex;
142 }
143 
151  if (!m_primclex) {
153  "Error in Supercell::primclex(): does not exist");
154  }
155  return *m_primclex;
156 }
157 
165 Index Supercell::sublat(Index linear_index) const {
166  return this->sym_info()
168  .sublattice();
169 }
170 
183 Index Supercell::linear_index(const Coordinate &coord, double tol) const {
184  Coordinate tcoord(coord);
185  tcoord.within();
187 }
188 
194  return this->sym_info().unitcellcoord_index_converter()(bijk);
195 }
196 
199 Coordinate Supercell::coord(Index linear_index) const {
200  UnitCellCoord linear_index_ucc =
202  return linear_index_ucc.coordinate(this->prim());
203 }
204 
211 }
212 
213 Eigen::VectorXi Supercell::max_allowed_occupation() const {
214  Index n_sublat = prim().basis().size();
215  Eigen::VectorXi max_allowed = Eigen::VectorXi::Zero(n_sublat * volume());
216 
217  for (Index b = 0; b < n_sublat; b++) {
218  int sublat_max = prim().basis()[b].occupant_dof().size() - 1;
219  max_allowed.segment(volume() * b, volume()) =
220  Eigen::VectorXi::Constant(volume(), sublat_max);
221  }
222 
223  return max_allowed;
224 }
225 
228  return this->sym_info().unitcell_index_converter().total_sites();
229 }
230 
231 Index Supercell::basis_size() const { return prim().basis().size(); }
232 
233 Index Supercell::num_sites() const { return volume() * basis_size(); }
234 
236  return this->sym_info().transformation_matrix_to_super();
237 }
238 
239 const Lattice &Supercell::lattice() const {
240  return this->sym_info().supercell_lattice();
241 }
242 
245  // if any additions to the prim nlist, must update the super nlist
246  if (primclex().shared_nlist()->size() != m_nlist_size_at_construction) {
247  m_nlist.unique().reset();
248  }
249 
250  // lazy construction of neighbor list
251  if (!m_nlist) {
253  m_nlist = notstd::make_cloneable<SuperNeighborList>(
254  this->sym_info().superlattice(), *primclex().shared_nlist());
255  }
256  return *m_nlist;
257 }
258 
259 // Factor group of this supercell
261  return sym_info().factor_group();
262 }
263 
264 // SymInfo object of this supercell
266 
267 bool Supercell::operator<(const Supercell &B) const {
268  if (shared_prim() != B.shared_prim()) {
269  throw std::runtime_error(
270  "Error using Supercell::operator<(const Supercell& B): "
271  "Only Supercell with shared prim may be compared this way.");
272  }
273  if (volume() != B.volume()) {
274  return volume() < B.volume();
275  }
276  return lattice() < B.lattice();
277 }
278 
283 std::pair<DB::DatabaseIterator<Supercell>, bool> Supercell::insert() const {
284  return primclex().db<Supercell>().emplace(
285  &primclex(), xtal::canonical::equivalent(lattice(), prim().point_group(),
287 }
288 
289 bool Supercell::eq_impl(const Supercell &B) const {
290  if (this == &B) {
291  return true;
292  }
293  if (shared_prim() != B.shared_prim()) {
294  throw std::runtime_error(
295  "Error using Supercell::operator==(const Supercell& B): "
296  "Only Supercell with shared prim may be compared this way.");
297  }
298  return transf_mat() == B.transf_mat();
299 }
300 
317 std::string Supercell::generate_name_impl() const {
318  return scelname(prim(), lattice());
319 }
320 
336 std::string make_supercell_name(Structure const &prim,
337  xtal::Superlattice const &superlattice) {
338  return make_supercell_name(prim.point_group(), prim.lattice(),
339  superlattice.superlattice());
340 }
341 
344  Structure const &prim, xtal::Superlattice const &superlattice) {
345  return make_canonical_supercell_name(prim.point_group(), prim.lattice(),
346  superlattice.superlattice());
347 }
348 
351  Structure const &prim, std::string supercell_name) {
353  prim.lattice(), supercell_name);
354 }
355 
357 Supercell &apply(const SymOp &op, Supercell &supercell) {
358  return supercell = copy_apply(op, supercell);
359 }
360 
362 Supercell copy_apply(const SymOp &op, const Supercell &supercell) {
363  Supercell result{supercell.shared_prim(),
364  sym::copy_apply(op, supercell.lattice())};
366  if (supercell.has_primclex()) {
367  result.set_primclex(&supercell.primclex());
368  }
369  return result;
370 }
371 
372 // --- The following are deprecated ----
373 
378 const Supercell &make_supercell(const PrimClex &primclex, std::string name) {
379  // check if scel is in database
380  const auto &db = primclex.db<Supercell>();
381  auto it = db.find(name);
382 
383  // if already in database, return ref
384  if (it != db.end()) {
385  return *it;
386  }
387 
388  std::vector<std::string> tmp, tokens;
389  try {
390  // else construct transf_mat from name (make sure to remove any empty
391  // tokens)
392  boost::split(tmp, name, boost::is_any_of("SCEL_"),
393  boost::token_compress_on);
394  std::copy_if(tmp.begin(), tmp.end(), std::back_inserter(tokens),
395  [](const std::string &val) { return !val.empty(); });
396  if (tokens.size() != 7) {
397  throw std::invalid_argument(
398  "Error in make_supercell: supercell name format error");
399  }
400  } catch (std::exception &e) {
401  std::string format = "SCELV_T00_T11_T22_T12_T02_T01";
402  err_log().error("In make_supercell");
403  err_log() << "expected format: " << format << "\n";
404  err_log() << "name: |" << name << "|" << std::endl;
405  err_log() << "tokens: " << tokens << std::endl;
406  err_log() << "tokens.size(): " << tokens.size() << std::endl;
407  err_log() << e.what() << std::endl;
408  throw e;
409  }
410 
411  Eigen::Matrix3l T;
412  try {
413  auto cast = [](std::string val) { return boost::lexical_cast<Index>(val); };
414  T << cast(tokens[1]), cast(tokens[6]), cast(tokens[5]), 0, cast(tokens[2]),
415  cast(tokens[4]), 0, 0, cast(tokens[3]);
416  } catch (std::exception &e) {
417  err_log().error("In make_supercell");
418  err_log() << "Could not construct transformation matrix from supercell name"
419  << std::endl;
420  err_log() << " name: " << name << std::endl;
421  err_log() << " tokens: " << tokens << std::endl;
422  err_log() << e.what() << std::endl;
423  throw e;
424  }
425 
426  // construct supercell, insert into database, and return result
427  Supercell scel(&primclex, T);
428  return *(scel.insert().first);
429 }
430 
433 std::shared_ptr<Supercell> make_shared_supercell(const PrimClex &primclex,
434  std::string name) {
435  // tokenize name
436  std::vector<std::string> tokens;
437  boost::split(tokens, name, boost::is_any_of("."), boost::token_compress_on);
438 
439  // validate name
440  if (tokens.size() != 2) {
441  std::string format = "$CANON_SCEL_NAME.$PRIM_FG_OP";
442  err_log().error("In make_shared_supercell");
443  err_log() << "expected format: " << format << "\n";
444  err_log() << "name: " << name << std::endl;
445  err_log() << "tokens: " << tokens << std::endl;
446  throw std::invalid_argument(
447  "Error in make_shared_supercell: supercell name format error");
448  }
449 
450  // generate scel lattice, and put in niggli form
451  Index fg_op_index = boost::lexical_cast<Index>(tokens[1]);
452  Lattice hnf_lat =
453  sym::copy_apply(primclex.prim().factor_group()[fg_op_index],
454  make_supercell(primclex, tokens[0]).lattice());
455  Lattice niggli_lat = niggli(hnf_lat, primclex.crystallography_tol());
456 
457  // construct Supercell
458  return std::make_shared<Supercell>(&primclex, niggli_lat);
459 }
460 
462 Eigen::Matrix3l transf_mat(const Lattice &prim_lat, const Lattice &super_lat,
463  double tol) {
464  auto res = xtal::is_superlattice(super_lat, prim_lat, tol);
465  if (!res.first) {
466  std::stringstream err_msg;
467  err_msg << "Error finding supercell transformation matrix:\n"
468  << " Bad supercell, the transformation matrix is not integer.\n\n"
469  << "superlattice: \n"
470  << super_lat.lat_column_mat() << "\n"
471  << "prim lattice: \n"
472  << prim_lat.lat_column_mat() << "\n"
473  << "tolerance: " << tol << "\n"
474  << "transformation matrix: \n"
475  << res.second << "\n";
476  throw std::invalid_argument(err_msg.str());
477  }
478  return lround(res.second);
479 }
480 
483  std::string name_str;
484 
485  Eigen::Matrix3i H = hermite_normal_form(transf_mat.cast<int>()).first;
486  name_str = "SCEL";
487  std::stringstream tname;
488  // Consider using a for loop with HermiteCounter_impl::_canonical_unroll here
489  tname << H(0, 0) * H(1, 1) * H(2, 2) << "_" << H(0, 0) << "_" << H(1, 1)
490  << "_" << H(2, 2) << "_" << H(1, 2) << "_" << H(0, 2) << "_" << H(0, 1);
491  name_str.append(tname.str());
492 
493  return name_str;
494 }
495 
497 std::string scelname(const Structure &prim, const Lattice &superlat) {
498  const SymGroup &pg = prim.point_group();
499  Lattice canon_lat = xtal::canonical::equivalent(superlat, pg);
500  std::string result = CASM::generate_name(
501  transf_mat(prim.lattice(), canon_lat, prim.lattice().tol()));
502  if (!xtal::is_equivalent(superlat, canon_lat)) {
503  auto to_canonical_ix = xtal::canonical::operation_index(superlat, pg);
504  result += ("." + std::to_string(pg[to_canonical_ix].inverse().index()));
505  }
506  return result;
507 }
508 
510 std::string canonical_scelname(const Structure &prim, const Lattice &superlat) {
511  const SymGroup &pg = prim.point_group();
512  return CASM::generate_name(
513  transf_mat(prim.lattice(), xtal::canonical::equivalent(superlat, pg),
514  prim.lattice().tol()));
515 }
516 
517 namespace xtal {
518 
521  IntegralCoordinateWithin_f bring_within_f(scel.transf_mat());
522  return bring_within_f;
523 }
524 } // namespace xtal
525 
526 } // namespace CASM
std::shared_ptr< Structure const > shared_prim
void error(const std::string &what)
Definition: Log.hh:129
PrimClex is the top-level data structure for a CASM project.
Definition: PrimClex.hh:55
Structure specifies the lattice and atomic basis of a crystal.
Definition: Structure.hh:30
const SymGroup & point_group() const
Definition: Structure.cc:110
const Lattice & lattice() const
Definition: Structure.hh:100
const std::vector< xtal::Site > & basis() const
Definition: Structure.hh:102
const MasterSymGroup & factor_group() const
Definition: Structure.cc:107
Represents a supercell of the primitive parent crystal structure.
Definition: Supercell.hh:51
Index sublat(Index linear_index) const
Return the sublattice index for a linear index.
Definition: Supercell.cc:165
Index linear_index(const Coordinate &coord, double tol=TOL) const
Given a Coordinate and tolerance, return linear index into Configuration.
Definition: Supercell.cc:183
SupercellSymInfo m_sym_info
Definition: Supercell.hh:170
UnitCellCoord uccoord(Index linear_index) const
Return the integral coordinates corresponding to a linear index.
Definition: Supercell.cc:209
Eigen::VectorXi max_allowed_occupation() const
returns maximum allowed occupation bitstring – used for initializing enumeration counters
Definition: Supercell.cc:213
const PrimClex & primclex() const
Use while transitioning Supercell to no longer need a PrimClex const *
Definition: Supercell.cc:150
double crystallography_tol() const
Definition: Supercell.cc:119
Coordinate coord(Index linear_index) const
Return the linear index corresponding to integral coordinates.
Definition: Supercell.cc:199
bool has_primclex() const
Use while transitioning Supercell to no longer need a PrimClex const *
Definition: Supercell.cc:127
bool operator<(const Supercell &B) const
Definition: Supercell.cc:267
Supercell(const Supercell &RHS)
Definition: Supercell.cc:36
const Lattice & lattice() const
The super lattice.
Definition: Supercell.cc:239
const SuperNeighborList & nlist() const
Returns the SuperNeighborList.
Definition: Supercell.cc:244
void set_primclex(PrimClex const *primclex_ptr) const
Use while transitioning Supercell to no longer need a PrimClex const *
Definition: Supercell.cc:136
Eigen::Matrix3l transf_mat() const
Definition: Supercell.cc:235
Index basis_size() const
Definition: Supercell.cc:231
std::pair< DB::DatabaseIterator< Supercell >, bool > insert() const
Insert the canonical form of this into the database.
Definition: Supercell.cc:283
PrimClex const * m_primclex
Definition: Supercell.hh:166
Index m_nlist_size_at_construction
Definition: Supercell.hh:178
std::shared_ptr< Structure const > m_shared_prim
Definition: Supercell.hh:168
notstd::cloneable_ptr< SuperNeighborList > m_nlist
SuperNeighborList, mutable for lazy construction.
Definition: Supercell.hh:173
Index num_sites() const
Definition: Supercell.cc:233
Index volume() const
Return number of primitive cells that fit inside of *this.
Definition: Supercell.cc:227
bool eq_impl(const Supercell &B) const
Definition: Supercell.cc:289
const SymGroup & factor_group() const
Definition: Supercell.cc:260
const Structure & prim() const
Definition: Supercell.cc:113
std::shared_ptr< Structure const > const & shared_prim() const
Definition: Supercell.cc:115
const SupercellSymInfo & sym_info() const
Definition: Supercell.cc:265
std::string generate_name_impl() const
Return supercell name.
Definition: Supercell.cc:317
A class that collects all symmetry information for for performing symmetry transformations on the sit...
const xtal::UnitCellCoordIndexConverter & unitcellcoord_index_converter() const
UnitCellCoordIndexConverter for this superstructure/primstructure pair Used to convert from lattice t...
SymGroup const & factor_group() const
Subgroup of primitive-cell factor group operations that leave supercell lattice invariant.
const xtal::UnitCellIndexConverter & unitcell_index_converter() const
UnitCellIndexConverter for this superlattice/primlattice pair Used to convert from lattice translatio...
const xtal::Lattice & supercell_lattice() const
const reference to supercell lattice
Eigen::Matrix3l transformation_matrix_to_super() const
long-int transformation from primitive lattice vectors to supercell lattice vectors supercell_lattice...
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
Definition: SymGroup.hh:42
SymOp is the Coordinate representation of a symmetry operation it keeps fraction (FRAC) and Cartesian...
Definition: SymOp.hh:28
Represents cartesian and fractional coordinates.
Definition: Coordinate.hh:34
const Eigen::Matrix3d & lat_column_mat() const
3x3 matrix with lattice vectors as its columne
Definition: Lattice.hh:110
double tol() const
Definition: Lattice.hh:195
const Lattice & superlattice() const
Definition: Superlattice.hh:18
Unit Cell Coordinates.
Coordinate coordinate(const PrimType &prim) const
Get corresponding coordinate.
static UnitCellCoord from_coordinate(const PrimType &, const Coordinate &coord, double tol)
Index total_sites() const
Returns the total number of sites within the superlattice.
std::string to_string(ENUM val)
Return string representation of enum class.
Definition: io_traits.hh:172
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.
Definition: Lattice.cc:836
Eigen::CwiseUnaryOp< decltype(Local::lround_l< typename Derived::Scalar >), const Derived > lround(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd to Eigen::MatrixXl.
std::pair< Eigen::MatrixXi, Eigen::MatrixXi > hermite_normal_form(const Eigen::MatrixXi &M)
Return the hermite normal form, M == H*V.
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.
DB::Database< T > & db() const
Definition: PrimClex.cc:302
std::shared_ptr< PrimNeighborList > const & shared_nlist() const
Access to the primitive neighbor list as a shared resource.
Definition: PrimClex.cc:270
double crystallography_tol() const
Get the crystallography_tol.
Definition: PrimClex.cc:233
const PrimType & prim() const
const Access to primitive Structure
Definition: PrimClex.cc:262
std::shared_ptr< Supercell > make_shared_supercell(const PrimClex &primclex, std::string name)
Definition: Supercell.cc:433
std::string generate_name(const Eigen::Matrix3l &transf_mat)
Make hermite normal form name [deprecated].
Definition: Supercell.cc:482
const Supercell & make_supercell(const PrimClex &primclex, std::string name)
Definition: Supercell.cc:378
xtal::Superlattice make_superlattice_from_supercell_name(Structure const &prim, std::string supercell_name)
Construct a Superlattice from the supercell name.
Definition: Supercell.cc:350
std::string canonical_scelname(const Structure &prim, const Lattice &superlat)
Make canonical supercell name name [deprecated].
Definition: Supercell.cc:510
std::string scelname(const Structure &prim, const Lattice &superlat)
Make supercell name name [deprecated].
Definition: Supercell.cc:497
std::string make_canonical_supercell_name(Structure const &prim, xtal::Superlattice const &superlattice)
Make the canonical supercell name from a Superlattice.
Definition: Supercell.cc:343
std::string make_supercell_name(Structure const &prim, xtal::Superlattice const &superlattice)
Make the supercell name from a Superlattice.
Definition: Supercell.cc:336
Supercell & apply(const SymOp &op, Supercell &scel)
Apply symmetry operation to Supercell.
Definition: Supercell.cc:357
Eigen::Matrix3l transf_mat(const Lattice &prim_lat, const Lattice &super_lat)
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
Lattice equivalent(Lattice const &in_lat, SymOpVector const &point_grp, double compare_tol)
Index operation_index(const Lattice &lat, SymOpVector const &g)
bool is_equivalent(const Lattice &ref_lattice, const Lattice &other)
Check if ref_lattice = other*U, where U is unimodular.
IntegralCoordinateWithin_f make_bring_within_f(const Supercell &scel)
Make IntegralCoordinateWithin_f for Supercell [deprecated].
Definition: Supercell.cc:520
Lattice niggli(const Lattice &in_lat, double compare_tol, bool keep_handedness=false)
Definition: Niggli.cc:330
Main CASM namespace.
Definition: APICommand.hh:8
MappingNode copy_apply(PermuteIterator const &_it, MappingNode const &_node, bool transform_cost_mat=true)
Reorders the permutation and compounds the spatial isometry (rotation.
GenericDatumFormatter< std::string, DataObject > name()
SupercellSymInfo make_supercell_sym_info(Structure const &prim, Lattice const &super_lattice)
Definition: Structure.cc:419
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
Log & err_log()
Definition: Log.hh:426
Matrix< long int, 3, 3 > Matrix3l
Definition: eigen.hh:12
PrimClex * primclex
Definition: settings.cc:135