CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
Lattice.cc
Go to the documentation of this file.
3 
6 #include "casm/symmetry/SymOp.hh"
7 
8 namespace CASM {
9 
10  namespace {
11 
12  typedef std::vector<Lattice>::iterator vec_lat_it;
13  typedef std::back_insert_iterator<std::vector<SymOp> > vec_symop_back_inserter;
14  typedef Array<SymOp>::const_iterator array_symop_cit;
15  }
16 
18  vec_lat_it, vec_lat_it, array_symop_cit, array_symop_cit);
19 
20  template vec_symop_back_inserter Lattice::find_invariant_subgroup<array_symop_cit, vec_symop_back_inserter>(
21  array_symop_cit, array_symop_cit, vec_symop_back_inserter, double) const;
22 
23  template std::pair<array_symop_cit, Eigen::MatrixXi> is_supercell<Lattice, array_symop_cit>(
24  const Lattice &, const Lattice &, array_symop_cit, array_symop_cit, double);
25 
26 
27  Lattice::Lattice(const Eigen::Vector3d &vec1,
28  const Eigen::Vector3d &vec2,
29  const Eigen::Vector3d &vec3) {
30  m_lat_mat << vec1, vec2, vec3;
31  m_inv_lat_mat = m_lat_mat.inverse();
32  }
33 
34  //********************************************************************
35 
38  Lattice::Lattice(const Eigen::Ref<const Eigen::Matrix3d> &lat_mat) :
39  m_lat_mat(lat_mat),
40  m_inv_lat_mat(lat_mat.inverse()) {
41  }
42 
43  //********************************************************************
44 
45  Lattice Lattice::fcc() {
46  Eigen::Matrix3d latmat;
47  latmat <<
48  0, 1, 1,
49  1, 0, 1,
50  1, 1, 0;
51  latmat /= pow(latmat.determinant(), 1.0 / 3.0);
52  return Lattice(latmat);
53  }
54 
55  //********************************************************************
56 
57  Lattice Lattice::bcc() {
58  Eigen::Matrix3d latmat;
59  latmat <<
60  -1, 1, 1,
61  1, -1, 1,
62  1, 1, -1;
63  latmat /= pow(latmat.determinant(), 1.0 / 3.0);
64  return Lattice(latmat);
65  }
66 
67  //********************************************************************
68 
69  Lattice Lattice::cubic() {
70  return Lattice(Eigen::Matrix3d::Identity());
71  }
72 
73  //********************************************************************
74 
75  Lattice Lattice::hexagonal() {
76  Eigen::Matrix3d latmat;
77  latmat <<
78  1, -1.0 / sqrt(3.0), 0,
79  0, 2.0 / sqrt(3.0), 0,
80  0, 0, sqrt(3.0);
81 
82  return Lattice(latmat.transpose());
83  }
84 
85  //********************************************************************
86 
87  Lattice Lattice::scaled_lattice(double scale) const {
88  return Lattice(scale * lat_column_mat());
89  }
90 
91  //********************************************************************
92  //Calculate length of lattice vector 'i'
93  double Lattice::length(Index i) const {
94  // Calculates Lengths
95  return m_lat_mat.col(i).norm();
96  }
97 
98  //********************************************************************
99  double Lattice::angle(Index i) const {
100  //double t_a = m_lat_mat.col((i + 1) % 3).dot(m_lat_mat.col((i + 2) % 3)) / (length((i + 1) % 3) * length((i + 2) % 3));
101  //Make sure that cos(angle) is between 0 and 1
102  //if((t_a - 1.0) > 0.0) {
103  //t_a = 1.0;
104  //}
105 
106  //if((t_a + 1.0) < 0.0) {
107  //t_a = -1.0;
108  //}
109 
110  //return (180.0 / M_PI) * acos(t_a);
111  return (180.0 / M_PI) * CASM::angle(m_lat_mat.col((i + 1) % 3), m_lat_mat.col((i + 2) % 3));
112  }
113 
114  //********************************************************************
115 
116  void Lattice::read(std::istream &stream) {
117  double scale;
118  stream >> scale;
119  stream >> m_lat_mat;
120  m_lat_mat *= scale;
121  m_lat_mat.transposeInPlace();
122  m_inv_lat_mat = m_lat_mat.inverse();
123 
124  return;
125  }
126 
127  //********************************************************************
128 
129  void Lattice::print(std::ostream &stream, int _prec) const {
130  int tprec = stream.precision();
131  std::ios::fmtflags tflags = stream.flags();
132  stream.precision(_prec);
133  stream.width(_prec + 3);
134  stream.flags(std::ios::showpoint | std::ios::fixed | std::ios::right);
135  stream << 1.0 << '\n';
136 
137  stream << ' ' << std::setw(_prec + 8) << m_lat_mat.col(0).transpose() << '\n';
138  stream << ' ' << std::setw(_prec + 8) << m_lat_mat.col(1).transpose() << '\n';
139  stream << ' ' << std::setw(_prec + 8) << m_lat_mat.col(2).transpose() << '\n';
140 
141  stream.precision(tprec);
142  stream.flags(tflags);
143 
144  return;
145  }
146 
147  //********************************************************************
148  //Gets the reciprocal lattice from the lattice vectors... (AAB)
149  Lattice Lattice::get_reciprocal() const {
150  /* Old Expression
151  return Lattice(2 * M_PI * cross_prod(vecs[1], vecs[2])/vol,
152  2 * M_PI * cross_prod(vecs[2], vecs[0]) / vol,
153  2 * M_PI * cross_prod(vecs[0], vecs[1]) / vol);
154  return recip_lat;
155  */
156  return Lattice(2 * M_PI * inv_lat_column_mat().transpose()); //equivalent expression
157  }
158 
159  //********************************************************************
160 
161  Array<int> Lattice::calc_kpoints(Array<int> prim_kpoints, Lattice prim_lat) {
162  Array<int> super_kpoints = prim_kpoints;
163  // Lattice prim_recip_lat = (lattice.primitive->get_reciprocal());
164  Lattice prim_recip_lat = (prim_lat.get_reciprocal());
165  Lattice recip_lat = (*this).get_reciprocal();
166  double prim_density = (prim_kpoints[0] * prim_kpoints[1] * prim_kpoints[2]) / (prim_recip_lat.vol());
167  double super_density = 0;
168 
169  // std::cout << prim_recip_lat << std::endl;
170  //std::cout << recip_lat << std::endl;
171 
172  Array<double> prim_vec_lengths;
173 
174  for(int i = 0; i < 3; i++) {
175  prim_vec_lengths.push_back(prim_recip_lat.length(i));
176  }
177  //std::cout<<prim_vec_lengths<<"\n";
178  double shortest = prim_vec_lengths.min();
179  int short_ind = prim_vec_lengths.find(shortest);
180 
181  //std::cout << "prim kpoints "<< prim_kpoints << std::endl;
182  // std::cout << "prim recip vol " << prim_recip_lat.vol << std::endl;
183  //std::cout << "prim kpoint density " << prim_density << std::endl;
184 
185  double scale = (prim_kpoints[short_ind] / shortest);
186 
187  for(int i = 0; i < 3; i++) {
188  super_kpoints[i] = int(ceil(scale * recip_lat.length(i)));
189  }
190 
191  super_density = (super_kpoints[0] * super_kpoints[1] * super_kpoints[2]) / (recip_lat.vol());
192 
193  //std::cout << "super kpoint density " << super_density << std::endl;
194  //std::cout << super_kpoints << std::endl;
195 
196  while(super_density < prim_density) {
197  // std::cout << prim_kpoints[short_ind] << std::endl;
198  prim_kpoints[short_ind]++;
199  //std::cout << prim_kpoints[short_ind] << std::endl;
200  scale = (prim_kpoints[short_ind] / shortest);
201  //std::cout << scale << std::endl;
202 
203  for(int i = 0; i < 3; i++) {
204  super_kpoints[i] = int(ceil(scale * recip_lat.length(i)));
205  }
206 
207  //std::cout << super_kpoints << std::endl;
208 
209  super_density = (super_kpoints[0] * super_kpoints[1] * super_kpoints[2]) / (recip_lat.vol());
210 
211  //std::cout << super_density << std::endl;
212  }
213  //std::cout << "---------------\n";
214 
215  return super_kpoints;
216  }
217 
218  //********************************************************************
219  // Finds subgroup of super_group that leaves this lattice invariant.
220  // note that this routine is written so that pg_tol has exactly the same meaning
221  // as in Lattice::generate_point_group
222  void Lattice::find_invariant_subgroup(const SymGroup &super_group, SymGroup &sub_group, double pg_tol) const {
223  if(sub_group.size() != 0) {
224  std::cerr << "WARNING in Lattice::find_invariant_group" << std::endl;
225  std::cerr << "The subgroup isn't empty and it's about to be rewritten!" << std::endl;
226  sub_group.clear();
227  }
228 
229  this->find_invariant_subgroup(super_group.begin(), super_group.end(), std::back_inserter(sub_group), pg_tol);
230  }
231 
232  //*******************************************************************************
233 
235  bool Lattice::is_canonical(double tol) const {
236  return almost_equal(this->lat_column_mat(), this->canonical_form(tol).lat_column_mat(), tol);
237  }
238 
239  //*******************************************************************************
240 
242  bool Lattice::is_canonical(const SymGroup &pg, double tol) const {
243  return almost_equal(this->lat_column_mat(), this->canonical_form(pg, tol).lat_column_mat(), tol);
244  }
245 
246  //*******************************************************************************
247 
250 
251  // canon = X*this
252  // canon.t = this.t * X.t
253 
254  Lattice canon {this->canonical_form(tol)};
255  return SymOp {(this->lat_column_mat().transpose()).colPivHouseholderQr().solve(canon.lat_column_mat().transpose()).transpose()};
256  }
257 
258  //*******************************************************************************
259 
261  SymOp Lattice::to_canonical(const SymGroup &pg, double tol) const {
262 
263  // canon = X*this
264  // canon.t = this.t * X.t
265 
266  Lattice canon {this->canonical_form(pg, tol)};
267  return SymOp {(this->lat_column_mat().transpose()).colPivHouseholderQr().solve(canon.lat_column_mat().transpose()).transpose()};
268  }
269 
270  //*******************************************************************************
271 
274  return to_canonical(tol).inverse();
275  }
276 
277  //*******************************************************************************
278 
280  SymOp Lattice::from_canonical(const SymGroup &pg, double tol) const {
281  return to_canonical(pg, tol).inverse();
282  }
283 
284  //*******************************************************************************
285 
289  Lattice Lattice::canonical_form(double tol) const {
290  SymGroup pg;
291  this->generate_point_group(pg, tol);
292  return this->canonical_form(pg, tol);
293  }
294 
295  //*******************************************************************************
296 
298  Lattice Lattice::canonical_form(const SymGroup &pg, double tol) const {
299  return canonical_equivalent_lattice(*this, pg, tol);
300  }
301 
302  //********************************************************************
303 
304  void Lattice::generate_point_group(SymGroup &point_group, double pg_tol) const {
305 
306  if(point_group.size() != 0) {
307  std::cerr << "WARNING in Lattice::generate_point_group" << std::endl;
308  std::cerr << "The point group for your lattice isn't empty and it's about to be rewritten!" << std::endl;
309  point_group.clear();
310  }
311 
312  point_group.set_lattice(*this);
313 
314  //Enumerate all possible matrices with elements equal to -1, 0, or 1
315  //These represent operations that reorder lattice vectors or replace one
316  //or more lattice vectors with a face or body diagonal.
317  Eigen::Matrix3d tMat, tOp_cart;
318  EigenCounter<Eigen::Matrix3i> pg_count(Eigen::Matrix3i::Constant(-1),
319  Eigen::Matrix3i::Constant(1),
320  Eigen::Matrix3i::Constant(1));
321 
322  //For this algorithm to work, lattice needs to be in reduced form.
323  Lattice tlat_reduced(get_reduced_cell());
324  LatticeIsEquivalent is_equiv(tlat_reduced, pg_tol);
325  do {
326  if(is_equiv(pg_count())) {
327  point_group.push_back(is_equiv.sym_op());
328  }
329  }
330  while(++pg_count);
331 
332  if(!point_group.is_group(pg_tol)) {
333  std::cerr << "*** WARNING *** \n"
334  << " Lattice::generate_point_group() has been called on an ill-conditioned lattice \n"
335  << " (i.e., a well-defined point group could not be found with the supplied tolerance of " << pg_tol << ").\n"
336  << " CASM will use the group closure of the symmetry operations that were found. Please consider using the \n"
337  << " CASM symmetrization tool on your input files.\n";
338  std::cout << "Lat_column_mat:\n" << lat_column_mat() << "\n\n";
339 
340  point_group.enforce_group(pg_tol);
341 
342  }
343  //Sort point_group by trace/conjugacy class
344  point_group.sort();
345 
346  return;
347  }
348 
349  //********************************************************************
350 
352  Array<double> tarray;
353  SymGroup point_group;
354  generate_point_group(point_group, large_tol);
355  if(!point_group.is_group(large_tol)) {
356  std::cout << "This is not a group. It is being enforced...\n";
357  point_group.enforce_group(large_tol);
358  }
359  for(Index i = 0; i < point_group.size(); i++) {
360  tarray.push_back(point_group[i].map_error());
361  }
362  return tarray;
363  }
364 
365 
366 
367  //********************************************************************
368 
369  void Lattice::pg_converge(double small_tol, double large_tol, double increment) {
370  Array<double> tols;
371  Array<bool> is_group, is_group_now;
372  Array<int> num_ops, num_enforced_ops;
373  Array<std::string> old_name, new_name;
374 
375  for(double i = small_tol; i <= large_tol; i += increment) {
376  SymGroup point_group;
377 
378  tols.push_back(i);
379  generate_point_group(point_group, i);
380  point_group.character_table();
381  old_name.push_back(point_group.get_name());
382  num_ops.push_back(point_group.size());
383  is_group.push_back(point_group.is_group(i));
384  point_group.enforce_group(i);
385  is_group_now.push_back(point_group.is_group(i));
386  num_enforced_ops.push_back(point_group.size());
387  point_group.character_table();
388  new_name.push_back(point_group.get_name());
389  }
390 
391  for(Index i = 0; i < tols.size(); i++) {
392  std::cout << tols[i] << "\t" << num_ops[i] << "\t" << is_group[i] << "\t" << old_name[i] << "\t" << num_enforced_ops[i] << "\t" << is_group_now[i] << "\t" << new_name[i] << "\n";
393  }
394 
395  return;
396  }
397 
398 
411  const SymGroup &effective_pg,
412  const ScelEnumProps &enum_props) const {
413 
414  SupercellEnumerator<Lattice> enumerator(*this, effective_pg, enum_props);
415  supercell.clear();
416  for(auto it = enumerator.begin(); it != enumerator.end(); ++it) {
417  supercell.push_back(canonical_equivalent_lattice(*it, effective_pg, TOL));
418  }
419  return;
420  }
421 
422 
423  //********************************************************************
442  Lattice Lattice::get_reduced_cell() const {
443 
444  int i, j, k, nv;
446  Eigen::Matrix3d tskew(Eigen::Matrix3d::Identity());
447  bool minimized = false;
448 
449  //std::cout << "Before reduction: \n";
450  //print(std::cout);
451 
452 
453  //Creates 12 skew matrices
454  //Do we also need the 12 "double skew" matrices corresponding to body diagonal substitution? YES
455  skew.reserve(24);
456  for(i = 0; i < 3; i++) {
457  for(j = 0; j < 3; j++) {
458  if(i != j) { //Checks to make sure we're not at a diagonal
459  tskew(i, j) = 1;
460  skew.push_back(tskew);
461  tskew(i, j) = -1;
462  skew.push_back(tskew);
463  tskew(i, j) = 0;
464  }
465  }
466  }
467 
468  //the 12 "double skew" matrices corresponding to body diagonal substitution
469  for(i = 0; i < 3; i++) { // column
470 
471  j = (i + 1) % 3;
472  k = (i + 2) % 3;
473 
474  tskew(j, i) = 1;
475  tskew(k, i) = 1;
476  skew.push_back(tskew);
477 
478  tskew(j, i) = 1;
479  tskew(k, i) = -1;
480  skew.push_back(tskew);
481 
482  tskew(j, i) = -1;
483  tskew(k, i) = 1;
484  skew.push_back(tskew);
485 
486  tskew(j, i) = -1;
487  tskew(k, i) = -1;
488  skew.push_back(tskew);
489 
490  tskew(j, i) = 0;
491  tskew(k, i) = 0;
492 
493  }
494 
495 
496  Eigen::Matrix3d tMat, reduced_lat_mat;
497  Eigen::Matrix3d tMat_mags, reduced_mags;
498  reduced_lat_mat = lat_column_mat(); //Matrix3
499  reduced_mags = reduced_lat_mat.transpose() * reduced_lat_mat;
500 
501  while(!minimized) {
502  minimized = true;
503  for(Index s = 0; s < skew.size(); s++) {
504 
505  //Multiply the original lattice (columns are lattice vectors) with the skew matrix
506  //Right multiply does elementary column operation on lattice vectors
507  tMat = (reduced_lat_mat * skew[s]);
508 
509  //Lattice vectors times their transpose give length and angle info
510  tMat_mags = tMat.transpose() * tMat;
511 
512  for(nv = 0; nv < 3; nv++) {
513  if(tMat_mags(nv, nv) < reduced_mags(nv, nv)) {
514  reduced_lat_mat = tMat;
515  reduced_mags = reduced_lat_mat.transpose() * reduced_lat_mat;
516  minimized = false;
517  s--; //try the same skew operator again.
518  break;
519  }
520  }
521  }
522  }
523 
524  Lattice reduced_lat(reduced_lat_mat);
525  return reduced_lat;
526  }
527 
528  //********************************************************************
529 
530  double Lattice::max_voronoi_measure(const Eigen::Vector3d &pos, Eigen::Vector3d &lattice_trans)const {
532  double maxproj = (voronoi_table() * pos).maxCoeff(&maxv);
533 
534  lattice_trans = (2.*floor(maxproj / 2. + (0.5 - TOL / 2.)) / m_voronoi_table.row(maxv).squaredNorm()) * m_voronoi_table.row(maxv);
535 
536  return maxproj;
537 
538  }
539 
540  //********************************************************************
541  int Lattice::voronoi_number(const Eigen::Vector3d &pos)const {
542 
543  int tnum = 0;
544  double tproj = 0;
545 
546  Eigen::MatrixXd const &vtable = voronoi_table();
547 
548  for(Index nv = 0; nv < vtable.size(); nv++) {
549  tproj = vtable.row(nv) * pos;
550  if(almost_equal(tproj, 1.0)) {
551  tnum++;
552  }
553  else if(tproj > 1.0) {
554  return -1;
555  }
556  }
557 
558 
559  return tnum;
560  }
561  //********************************************************************
562 
564  //There are no fewer than 12 points in the voronoi table
565  m_voronoi_table.resize(12, 3);
566 
567  m_inner_voronoi_radius = 1e20;
568 
569  Eigen::Vector3d tpoint;
570  int i;
571  int nrows = 1;
572  Lattice tlat_reduced(get_reduced_cell());
573 
574  //Count over all lattice vectors, face diagonals, and body diagonals
575  //originating from origin;
576  EigenCounter<Eigen::Vector3i > combo_count(Eigen::Vector3i(-1, -1, -1),
577  Eigen::Vector3i(1, 1, 1),
578  Eigen::Vector3i(1, 1, 1));
579 
580 
581  //For each linear combination, check to see if it is on a face, edge, or vertex of the voronoi cell
582  for(; combo_count.valid(); ++combo_count) {
583  if(combo_count().isZero()) continue;
584  //A linear combination does not fall on the voronoi boundary if the angle between
585  //any two of the vectors forming that combination are acute
586  for(i = 0; i < 3; i++) {
587  if(combo_count[(i + 1) % 3] == 0 || combo_count[(i + 2) % 3] == 0)
588  continue;
589  if((180. / M_PI)*CASM::angle(combo_count[(i + 1) % 3]*tlat_reduced[(i + 1) % 3], combo_count[(i + 2) % 3]*tlat_reduced[(i + 2) % 3]) + TOL < 90.) {
590  break;
591  }
592  }
593 
594  if(i == 3) {
595  if(nrows > m_voronoi_table.rows())
596  m_voronoi_table.conservativeResize(nrows, Eigen::NoChange);
597 
598  tpoint = tlat_reduced.lat_column_mat() * combo_count().cast<double>();
599 
600  double t_rad = tpoint.norm();
601  if((t_rad / 2.) < m_inner_voronoi_radius)
602  m_inner_voronoi_radius = t_rad / 2.;
603 
604  m_voronoi_table.row(nrows - 1) = (2. / (t_rad * t_rad)) * tpoint;
605  nrows++;
606  }
607 
608  }
609  return;
610  }
611 
612  //********************************************************************
625  //********************************************************************
626  Eigen::Vector3i Lattice::enclose_sphere(double radius) const {
627 
628  // reciprocal vectors
629  Eigen::Matrix3d recip(inv_lat_column_mat().transpose());
630 
631  for(int i = 0; i < 3; i++) {
632  recip.col(i) *= radius / recip.col(i).norm();
633  }
634  //recip contains three column vectors of length 'radius' pointed along plane normals
635  auto lambda = [](double val) {
636  return ceil(val);
637  };
638  return (inv_lat_column_mat() * recip).cwiseAbs().unaryExpr(lambda).colwise().maxCoeff().cast<int>();
639  }
640 
641  //********************************************************************
642  //Change bool to an array of SymOps you want to use, default point group
643  //Overload to only use identity
644  //Return N matrix
645  bool Lattice::is_supercell_of(const Lattice &tile, const Array<SymOp> &symoplist, Eigen::Matrix3d &multimat, double _tol) const {
646  auto result = is_supercell(*this, tile, symoplist.begin(), symoplist.end(), _tol);
647  multimat = result.second.cast<double>();
648  return result.first != symoplist.end();
649  }
650 
651  //********************************************************************
652  //Change bool to an array of SymOps you want to use, default point group
653  //Overload to only use identity
654  //Return N matrix
655  bool Lattice::is_supercell_of(const Lattice &tile, Eigen::Matrix3d &multimat, double _tol) const {
656  auto result = is_supercell(*this, tile, _tol);
657  multimat = result.second.cast<double>();
658  return result.first;
659  }
660 
661  //********************************************************************
662  //Overload to only use identity
663  //Return N matrix
664  bool Lattice::is_supercell_of(const Lattice &tile, double _tol) const {
665  return is_supercell(*this, tile, _tol).first;
666  }
667 
668  //********************************************************************
669 
670  bool Lattice::is_supercell_of(const Lattice &tile, const Array<SymOp> &symoplist, double _tol) const {
671  return is_supercell(*this, tile, symoplist.begin(), symoplist.end(), _tol).first != symoplist.end();
672  }
673 
682 
683  if(lat_column_mat().determinant() < 0) {
684  m_lat_mat = -m_lat_mat;
685  m_inv_lat_mat = m_lat_mat.inverse();
686  }
687 
688  return *this;
689  }
690 
691  //\John G 121212
692  //********************************************************************************************************
693 
694  Eigen::Vector3i Lattice::get_millers(Eigen::Vector3d plane_normal, double tolerance) const {
695  //Get fractional coordinates of plane_normal in recip_lattice
696  //These are h, k, l
697  //For miller indeces h, k and l plane_normal[CART]=h*a.recip+k*b.recip+l*c.recip
698  return scale_to_int(lat_column_mat().transpose() * plane_normal, tolerance);
699  }
700 
701  //John G 121015
702  //********************************************************************
715  //********************************************************************
716 
717  Lattice Lattice::get_lattice_in_plane(Eigen::Vector3i millers, int max_vol) const { //John G 121030
718  //Hold new lattice vectors in these. Then at the end we make an actual Lattice out of it
719  Eigen::Matrix3d surface_cell, last_surface_cell; //Holds new lattice vectors, two of which are in the surface plane
720 
721  //Miller indeces of 100, 010 or 001 mean you don't need a new cell to expose the plane, however
722  //you may want to reorient the vectors so that the ab plane is exposed (useful for Structure::stitch)
723 
724  if(millers == Eigen::Vector3i(0, 1, 0)) {
725  std::cout << "No chopping neccesary" << std::endl;
726  std::cout << "Flipping your vectors to bring a and b into plane:" << std::endl;
727  std::cout << "b --> c" << std::endl;
728  std::cout << "a --> b" << std::endl;
729  std::cout << "c --> a" << std::endl;
730  return Lattice(lat_column_mat().col(2), lat_column_mat().col(0), lat_column_mat().col(1));
731  }
732 
733  else if(millers == Eigen::Vector3i(1, 0, 0)) {
734  std::cout << "No chopping neccesary" << std::endl;
735  std::cout << "Flipping your vectors to bring a and b into plane:" << std::endl;
736  std::cout << "a --> c" << std::endl;
737  std::cout << "b --> a" << std::endl;
738  std::cout << "c --> b" << std::endl;
739  return Lattice(lat_column_mat().col(1), lat_column_mat().col(2), lat_column_mat().col(0));
740  }
741 
742  else if(millers == Eigen::Vector3i(0, 0, 1)) { // || millers==Eigen::Vector3i(0,1,0) || millers==Eigen::Vector3i(1,0,0))
743  return *this;
744  }
745 
746  //Miller indeces of xx0, 0xx or x0x mean one of the lattice vectors is the same as
747  //one of the primitive lattice vectors. This means we only need to get TWO
748  //points that are on the plane, which we connect to get the second lattice vector
749  else if(millers[0] == 0 || millers[1] == 0 || millers[2] == 0) {
750  int zero = 0;
751 
752  //Find out which miller index is 0
753  while(true) {
754  if(millers[zero] == 0) {
755  break;
756  }
757 
758  else {
759  zero++;
760  }
761  }
762 
763  surface_cell.col(0) = lat_column_mat().col(zero);
764 
765  Eigen::Vector3d H_miller_point, K_miller_point;
766  Eigen::Vector3d HK;
767  Eigen::Vector3d millers_dubs;
768 
769  //Turn integer millers into doubles for mathematical purposes (inverse)
770  millers_dubs = millers.cast<double>();
771 
772  //std::cout<<millers_dubs<<std::endl;
773 
774  Eigen::Vector3d inv_miller_dubs;
775  Eigen::Vector3i inv_miller;
776 
777 
778  //In actualility, the inverse miller of 0 is infinity, we set it to 0 here so that we can use
779  //scale_to_int without going crazy. Since we won't be using this inverse miller index it's OK
780  inv_miller_dubs[zero] = 0;
781  inv_miller_dubs[(zero + 1) % 3] = 1.0 / millers_dubs[(zero + 1) % 3];
782  inv_miller_dubs[(zero + 2) % 3] = 1.0 / millers_dubs[(zero + 2) % 3];
783 
784  inv_miller = scale_to_int(inv_miller_dubs, TOL);
785  H_miller_point = inv_miller[(zero + 1) % 3] * lat_column_mat().col((zero + 1) % 3);
786  K_miller_point = inv_miller[(zero + 2) % 3] * lat_column_mat().col((zero + 2) % 3);
787 
788  std::cout << "inv millers dubs: " << inv_miller_dubs << std::endl;
789  std::cout << "inv millers : " << inv_miller << std::endl;
790 
791  HK = K_miller_point - H_miller_point;
792  surface_cell.col(1) = HK;
793  }
794 
795 
796 
797  else {
798  //Get three points that lie on the plane
799  //We'll want to find points that lie on the plane AND land of lattice points. In order to do
800  //this we need the miller inverses multiplied by a factor that makes them integers
801  Eigen::Vector3d H_miller_point, K_miller_point, L_miller_point;
802  Eigen::Vector3d inv_miller_dubs;
803  Eigen::Vector3i inv_miller;
804  //Turn integer millers into doubles for mathematical purposes (inverse)
805  Eigen::Vector3d millers_dubs;
806  millers_dubs = millers.cast<double>();
807 
808  inv_miller_dubs[0] = 1.0 / millers_dubs[0];
809  inv_miller_dubs[1] = 1.0 / millers_dubs[1];
810  inv_miller_dubs[2] = 1.0 / millers_dubs[2];
811 
812  inv_miller = scale_to_int(inv_miller_dubs, TOL);
813 
814  H_miller_point = inv_miller[0] * lat_column_mat().col(0);
815  K_miller_point = inv_miller[1] * lat_column_mat().col(1);
816  L_miller_point = inv_miller[2] * lat_column_mat().col(2);
817 
818  //Get three vectors that connect the three points on the plane to each other. Any two of the following
819  //vectors could be used for constructing the new lattice, but it's convenient to pick the two
820  //most orthogonal vectors
821  Eigen::Vector3d HK, KL, LH;
822  Eigen::Vector3d tangles;
823 
824 
825  HK = K_miller_point - H_miller_point;
826  KL = L_miller_point - K_miller_point;
827  LH = H_miller_point - L_miller_point;
828 
829  //John G 121212
830  //The vectors that we got at this point are valid, but sometimes larger than they need to be.
831  Eigen::Matrix3d templat;
832  templat.col(0) = HK;
833  templat.col(1) = KL;
834  templat.col(2) = LH;
835 
836  //Find shortest vector
837  int s = 0;
838  for(int i = 1; i < 3; i++) {
839  if(lat_column_mat().col(i).norm() < lat_column_mat().col(s).norm()) {
840  s = i;
841  }
842  }
843 
844  //Try dividing by integers and see if they're still lattice combinations. If they are
845  //shorten and continue
846  for(int i = 0; i < 3; i++) {
847  int maxval = round(templat.col(i).norm() / lat_column_mat().col(i).norm() + 1);
848  for(int j = maxval; j > 1; j--) {
849  Eigen::Vector3d shortened = inv_lat_column_mat() * templat.col(i) / j; //Shorten and convert to fractional
850  bool combo = true;
851 
852  for(int k = 0; k < 3; k++) {
853  if(!almost_zero(std::abs(round(shortened[k]) - shortened[k]))) {
854  combo = false;
855  break;
856  }
857  }
858 
859  if(combo) {
860  templat.col(i) = lat_column_mat() * shortened;
861  break;
862  }
863  }
864  }
865 
866  HK = templat.col(0);
867  KL = templat.col(1);
868  LH = templat.col(2);
869 
870  //We select the two vectors that spawn the smallest area
871 
872  double HKKL, KLLH, LHHK;
873  HKKL = HK.cross(KL).norm();
874  KLLH = KL.cross(LH).norm();
875  LHHK = LH.cross(HK).norm();
876 
877  if(HKKL <= KLLH && HKKL <= LHHK) {
878  surface_cell.col(0) = HK;
879  surface_cell.col(1) = KL;
880  }
881 
882  else if(KLLH <= HKKL && KLLH <= LHHK) {
883  surface_cell.col(0) = KL;
884  surface_cell.col(1) = LH;
885  }
886 
887  else {
888  surface_cell.col(0) = LH;
889  surface_cell.col(1) = HK;
890  }
891  }
892  //\John G 121212
893  //We now have lattice vectors a and b. The c vector can be any vector that is a linear combination
894  //of the original primitive cell lattice vectors. Ideally the vector will be short and orthogonal
895  //to the plane.
896  Eigen::Vector3d normal;
897  Eigen::Vector3i L_combination;
898  int factor;
899 
900 
901  normal = inv_lat_column_mat() * surface_cell.col(0).cross(surface_cell.col(1)); //101112
902  factor = 1;
903 
904  //Divide by largest value in normal vector. We'll do something similar to when finding the miller
905  //indeces. We'll approximate the real normal vector with an integer normal vector, increasing
906  //the "resolution" of the integer vector in steps, until the desired accuary is reached.
907  if(fabs(normal[0]) >= fabs(normal[1]) && fabs(normal[0]) >= fabs(normal[2]) && normal[0] != 0) {
908  normal = normal / normal[0];
909  }
910 
911 
912  else if(fabs(normal[1]) >= fabs(normal[2]) && fabs(normal[1]) >= fabs(normal[0]) && fabs(normal[1]) != 0) {
913  normal = normal / normal[1];
914  }
915 
916  else {
917  normal = normal / normal[2];
918  }
919 
920  std::cout << "New cell vectors a and b have been generated:" << std::endl;
921  std::cout << "Vector A: <" << surface_cell.col(0) << ">" << std::endl;
922  std::cout << "Vector B: <" << surface_cell.col(1) << ">" << std::endl;
923  std::cout << "Gamma :" << (180 / M_PI)*CASM::angle(surface_cell.col(0), surface_cell.col(1)) << "\u00B0" << std::endl << std::endl;
924  std::cout << "Ready to make C..." << std::endl;
925 
926  Eigen::Vector3d tnormal;
927  //orthoscore represents how close the linear combination is to the plane normal. 1 is perfect, 0 is stupid.
928  double orthoscore = 1;
929  double torthoscore = 0;
930 
931  tnormal = normal;
932  double new_vol;
933  bool one_found = false;
934  do {
935  normal = tnormal * factor;
936 
937  //Get linear combinations by rounding the normal to integers
938  L_combination[0] = int(floor(normal[0] + 0.5));
939  L_combination[1] = int(floor(normal[1] + 0.5));
940  L_combination[2] = int(floor(normal[2] + 0.5));
941 
942  //After getting the normal vector in terms of integers, make a linear combination of the initial
943  //lattice vectors to get third new lattice vector
944  surface_cell.col(2) = lat_column_mat() * L_combination.cast<double>();
945  orthoscore = fabs(cos(CASM::angle(lat_column_mat() * normal, surface_cell.col(2))));
946  //Only use new linear combination if it's more orthogonal than the previous one
947  if(orthoscore > torthoscore + TOL) {
948  torthoscore = orthoscore;
949  std::cout << "Attempt No." << factor << " to get third lattice vector:" << std::endl;
950  std::cout << "Combine: " << L_combination[0] << "*a+" << L_combination[1] << "*b+" << L_combination[2] << "*c" << std::endl << std::endl;
951  std::cout << "Cell overview:" << std::endl;
952  std::cout << "Orthogonality score: " << orthoscore << std::endl;
953  std::cout << "Vector A: <" << surface_cell.col(0) << " >" << std::endl;
954  std::cout << "Vector B: <" << surface_cell.col(1) << " >" << std::endl;
955  std::cout << "Vector C: <" << surface_cell.col(2) << " >" << std::endl << std::endl;
956  std::cout << "Alpha :" << (180 / M_PI)*CASM::angle(surface_cell.col(1), surface_cell.col(2)) << "\u00B0" << std::endl << std::endl;
957  std::cout << "Beta :" << (180 / M_PI)*CASM::angle(surface_cell.col(2), surface_cell.col(0)) << "\u00B0" << std::endl << std::endl;
958  std::cout << "Gamma :" << (180 / M_PI)*CASM::angle(surface_cell.col(0), surface_cell.col(1)) << "\u00B0" << std::endl << std::endl << std::endl;
959 
960  last_surface_cell = surface_cell; //Remember currect generated cell, in case we can't find anything better later
961  one_found = true;
962 
963  new_vol = fabs(surface_cell.col(2).dot(surface_cell.col(0).cross(surface_cell.col(1))));
964 
965  std::cout << "Volume: " << new_vol << std::endl;
966  std::cout << "Volume equivalent to " << new_vol / vol() << " primitive volumes" << std::endl << std::endl;
967  }
968 
969  factor++;
970 
971  if(factor == 100) {
972  if(!one_found) {
973  throw std::runtime_error("failed get_lattice_in_plane");
974  }
975  std::cerr << "Reached an outrageous size. Returning last generated cell" << std::endl;
976  surface_cell = last_surface_cell;
977  break;
978  }
979 
980  }
981  while(new_vol / vol() < max_vol && orthoscore < 1); //John G 121030
982 
983  //std::cout<<"SURFACE:"<<surface_cell<<std::endl;
984 
985  Lattice surface_lat(surface_cell.col(0), surface_cell.col(1), surface_cell.col(2));
986  surface_lat.make_right_handed();
987  SymGroup surf_lat_pg;
988 
989  surface_lat.generate_point_group(surf_lat_pg);
990 
991  Eigen::Matrix3d transmat;
992  surface_lat.is_supercell_of(*this, surf_lat_pg, transmat);
993 
994  std::cout << "Your conversion matrix was:" << std::endl << transmat << std::endl;
995 
996  return surface_lat;
997  }
998 
999  //********************************************************************
1000 
1002  bool Lattice::is_equivalent(const Lattice &RHS, double tol) const {
1003  LatticeIsEquivalent f(*this, tol);
1004  return f(RHS);
1005  }
1006 
1007  //********************************************************************
1008 
1013  bool Lattice::operator<(const Lattice &RHS) const {
1014  bool A_is_niggli = is_niggli(*this, TOL);
1015  bool B_is_niggli = is_niggli(RHS, TOL);
1016  if(A_is_niggli != B_is_niggli) {
1017  return B_is_niggli;
1018  }
1019 
1021  }
1022 
1024  bool Lattice::_eq(const Lattice &RHS) const {
1025  return almost_equal(RHS.lat_column_mat(), lat_column_mat());
1026  }
1027 
1028 
1029  //John G 011013
1030  //********************************************************************
1036  //********************************************************************
1037 
1038  void Lattice::symmetrize(const SymGroup &relaxed_pg) {
1039  Eigen::Matrix3d tLat2(Eigen::Matrix3d::Zero());
1040  Eigen::Matrix3d frac_mat;
1041  for(Index ng = 0; ng < relaxed_pg.size(); ng++) {
1042  frac_mat = iround(inv_lat_column_mat() * relaxed_pg[ng].matrix() * lat_column_mat()).cast<double>();
1043  tLat2 += frac_mat.transpose() * lat_column_mat().transpose() * lat_column_mat() * frac_mat;
1044  }
1045 
1046  tLat2 /= double(relaxed_pg.size());
1047 
1048  // tLat2 has the symmetrized lengths and angles -- it is equal to L.transpose()*L, where L=lat_column_mat()
1049  // we will find the sqrt of tLat2 and then reorient it so that it matches the original lattice
1050  Eigen::Matrix3d tMat(tLat2), tMat2;
1051 
1052  Eigen::JacobiSVD<Eigen::Matrix3d> tSVD(tMat);
1053  tMat = Eigen::Matrix3d::Zero();
1054  for(int i = 0; i < 3; i++) {
1055  tMat(i, i) = tSVD.singularValues()[i];
1056  }
1057 
1058  tMat2 = tSVD.matrixU() * tMat * tSVD.matrixV().transpose();
1059 
1060  tMat = lat_column_mat();
1061 
1062  tSVD.compute(tMat2 * tMat.transpose());
1063 
1064  tMat = tSVD.matrixV() * tSVD.matrixU().transpose() * tMat2;
1065 
1066  for(int i = 0; i < 3; i++) {
1067  for(int j = 0; j < 3; j++) {
1068  tLat2(i, j) = tMat(i, j);
1069  }
1070  }
1071 
1072  (*this) = Lattice(tLat2);
1073 
1074 
1075 
1076  return;
1077  }
1078 
1079  //***********************************************************
1085  //***********************************************************
1086 
1087  void Lattice::symmetrize(double tol) {
1088  SymGroup point_group;
1089  generate_point_group(point_group, tol);
1090  symmetrize(point_group);
1091  return;
1092  }
1093 
1094  //***********************************************************
1095 
1097  if(vol() < 0) {
1098  return false;
1099  }
1100  else {
1101  return true;
1102  }
1103  }
1104 
1105  //********************************************************************
1106  // write Lattice in json as array of vectors
1107  jsonParser &to_json(const Lattice &lat, jsonParser &json) {
1108  json.put_array();
1109  json.push_back(lat[0]);
1110  json.push_back(lat[1]);
1111  json.push_back(lat[2]);
1112  return json;
1113  };
1114 
1115  //********************************************************************
1116  // read Lattice from a json array of Eigen::Vector3d
1117  void from_json(Lattice &lat, const jsonParser &json) {
1118  try {
1119  lat = Lattice(json[0].get<Eigen::Vector3d >(), json[1].get<Eigen::Vector3d >(), json[2].get<Eigen::Vector3d >());
1120  }
1121  catch(...) {
1123  throw;
1124  }
1125  };
1126 
1128  Lattice &apply(const SymOp &op, Lattice &lat) {
1129  return lat = Lattice(op.matrix() * lat.lat_column_mat());
1130  }
1131 
1133  Lattice copy_apply(const SymOp &op, const Lattice &lat) {
1134  return Lattice(op.matrix() * lat.lat_column_mat());
1135  }
1136 
1137 
1140  //*******************************************************************************************
1141  //
1142  // Finds "superduper" Lattice L_{sd} (represented as a matrix with lattice vectors as its columns
1143  // such that L_{sd} satisfies
1144  // L_{sd} = L_1 * N_1 = L_2 * N_2, (*1*)
1145  // where N_1 and N_2 are integer matrices such that Eq.(*1*) is satisfied and det(N_1) and det(N_2) are minimized.
1146  //
1147  // It is assumed that L_1 = L * M_1 and L_2 = L * M_2 (i.e., L_1 and L_2 are supercells of PRIM lattice L having
1148  // integer transformation matrices M_1 and M_2, respectively).
1149  //
1150  // Algorithm proceeds by noting inv(L_2)*L_1 = N_2*inv(N_1) = inv(M_2)*inv(M_1) = A/n, where A is an integer matrix and n = det(M_2). Assuming that
1151  // 'n' is small (n<10000), we can attempt to find 'n' and 'A'.
1152  //
1153  // Solution: N_2 = A*N_1/n, s.t. det(N_1) is minimized and N_2 is integer
1154  //
1155  // To minimize det(N_1), find smith normal form A = U*S*V, where U and V have det(1), S is diagonal,
1156  // and all entries are integer. Then choose N_1 = inv(V)*R, where R is a diagonal integer matrix with entries
1157  // R(i,i)=n/gcf(S(i,i),n)
1158  // The resulting solution will have det(M_1*N_1)>=lcm(det(M_1),det(M_2))
1159  //
1160  //*******************************************************************************************
1161  Lattice superdupercell(const Lattice &lat1, const Lattice &lat2) {
1162 
1164  long N = 1, num, denom;
1165  for(Index i = 0; i < 3; i++) {
1166  for(Index j = 0; j < 3; j++) {
1167  nearest_rational_number(dA(i, j), num, denom);
1168  dA *= double(denom);
1169  N *= denom;
1170  }
1171  }
1172 
1173  //std::cout << "dA is:\n" << dA << "\n\n";
1174  //std::cout << "and N is:\n" << N << "\n\n";
1175  Eigen::Matrix3l U, S, V;
1176  smith_normal_form(lround(dA), U, S, V);
1177  //std::cout << "Smith U is:\n" << U << "\n\n";
1178  //std::cout << "Smith S is:\n" << S << "\n\n";
1179  //std::cout << "Smith V is:\n" << V << "\n\n";
1180  //std::cout << "and U*S*V is:\n" << U*S*V << "\n\n";
1181  denom = N;
1182 
1183  //reuse matrix S for matrix 'R', as above
1184  for(Index i = 0; i < 3; i++) {
1185  S(i, i) = N / gcf(S(i, i), N);
1186  }
1187  //Matrix 'N_1', as above is now equal to inverse(V) * S
1188 
1189  Lattice tlat(lat1.lat_column_mat() * (inverse(V)*S).cast<double>());
1190  return tlat.get_reduced_cell();
1191  }
1192 
1193  //*******************************************************************************************
1194 
1196  std::pair<bool, Eigen::MatrixXi> is_supercell(const Lattice &scel, const Lattice &unit, double tol) {
1197  // check scel = unit*T, with integer T
1199 
1200  if(is_integer(T, tol) && !almost_zero(T)) {
1201  return std::make_pair(true, iround(T));
1202  }
1203  return std::make_pair(false, T.cast<int>());
1204  }
1205 
1214  Lattice replace_vector(const Lattice &lat, const Eigen::Vector3d &new_vector, double tol) {
1215 
1216  // replace a lattice vector with translation
1217  Lattice new_lat {lat};
1218  double min_vol = std::abs(volume(new_lat));
1219 
1220  for(int i = 0; i < 3; i++) {
1221 
1222  Lattice tmp_lat = lat;
1223  tmp_lat[i] = new_vector;
1224  double vol = std::abs(volume(tmp_lat));
1225 
1226  if(vol < min_vol && vol > tol) {
1227  min_vol = vol;
1228  new_lat = tmp_lat;
1229  }
1230 
1231  }
1232 
1233  return new_lat;
1234  }
1235 
1236 }
const SymOp * const_iterator
Definition: Array.hh:76
Eigen::MatrixXd MatrixXd
void _generate_voronoi_table() const
populate voronoi information.
Definition: Lattice.cc:563
Eigen::Matrix3d m_inv_lat_mat
Definition: Lattice.hh:269
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].
virtual void sort()
Sort SymOp in the SymGroup.
Definition: SymGroup.cc:3574
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:41
bool is_canonical(double tol=TOL) const
Check if Lattice is in the canonical form.
Definition: Lattice.cc:235
SymOp sym_op() const
Return the SymOp, constructed from the map_error and cart_op stored after performing an equivalence c...
Lattice superdupercell(const Lattice &lat1, const Lattice &lat2)
returns Lattice that is smallest possible supercell of both input Lattice
Definition: Lattice.cc:1161
void from_json(ClexDescription &desc, const jsonParser &json)
A Counter allows looping over many incrementing variables in one loop.
Definition: Counter.hh:71
Index size() const
Definition: Array.hh:145
void generate_point_group(SymGroup &point_group, double pg_tol=TOL) const
Populate.
Definition: Lattice.cc:304
Array< double > pg_converge(double large_tol)
Definition: Lattice.cc:351
int gcf(int i1, int i2)
Find greatest common factor.
Definition: CASM_math.cc:92
double length(Index i) const
Return length of i'th lattice vector.
Definition: Lattice.cc:93
void push_back(const T &toPush)
Definition: Array.hh:513
virtual void clear()
Definition: SymGroup.cc:490
static Lattice hexagonal()
Construct cubic primitive cell of unit volume.
Definition: Lattice.cc:75
bool _eq(const Lattice &RHS) const
Are lattice vectors identical for two lattices, within TOL.
Definition: Lattice.cc:1024
bool is_equivalent(const Lattice &RHS, double tol) const
Are two lattices the same, even if they have different lattice vectors.
Definition: Lattice.cc:1002
jsonParser & to_json(const ClexDescription &desc, jsonParser &json)
Data structure for holding supercell enumeration properties.
Object copy_apply(const Transform &f, Object obj, Args &&...args)
const_iterator end() const
A const iterator to the past-the-last volume.
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.
Definition: Niggli.cc:391
Eigen::MatrixXd const & voronoi_table() const
Return voronoi table, which specifies outward-pointing normals of Lattice Voronoi cell...
Definition: Lattice.hh:90
Lattice get_reduced_cell() const
Find the lattice vectors which give most compact unit cell Compactness is measured by how close lat_c...
Definition: Lattice.cc:442
A fake container of supercell matrices.
Definition: Enumerator.hh:407
Main CASM namespace.
Definition: complete.cpp:8
void print(std::ostream &stream, int _prec=8) const
Definition: Lattice.cc:129
template Lattice superdupercell< vec_lat_it, array_symop_cit >(vec_lat_it, vec_lat_it, array_symop_cit, array_symop_cit)
static Lattice bcc()
Construct BCC primitive cell of unit volume.
Definition: Lattice.cc:57
const double TOL
const Eigen::Matrix3d & lat_column_mat() const
3x3 matrix with lattice vectors as its columne
Definition: Lattice.hh:104
template std::pair< array_symop_cit, Eigen::MatrixXi > is_supercell< Lattice, array_symop_cit >(const Lattice &, const Lattice &, array_symop_cit, array_symop_cit, double)
Lattice get_lattice_in_plane(Eigen::Vector3i millers, int max_vol=20) const
Generates a lattice with vectors a and b parallel to the plane described by the miller indeces...
Definition: Lattice.cc:717
Putting all the Lattice comparisons in one place.
double m_inner_voronoi_radius
Definition: Lattice.hh:261
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
Definition: SymGroup.hh:33
double tol
Eigen::MatrixXd m_voronoi_table
Definition: Lattice.hh:262
const matrix_type & matrix() const
Const access of entire cartesian symmetry matrix.
Definition: SymOp.hh:57
Lattice replace_vector(const Lattice &lat, const Eigen::Vector3d &new_vector, double tol)
Returns a minimum volume Lattice obtainable by replacing one Lattice vector with tau.
Definition: Lattice.cc:1214
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:113
void clear()
Definition: Array.hh:216
Lattice(const Eigen::Vector3d &vec1, const Eigen::Vector3d &vec2, const Eigen::Vector3d &vec3)
Definition: Lattice.cc:27
const_iterator begin() const
A const iterator to the beginning volume, specify here how the iterator should jump through the enume...
static Lattice cubic()
Construct simple cubic primitive cell of unit volume.
Definition: Lattice.cc:69
SymOp is the Coordinate representation of a symmetry operation it keeps fraction (FRAC) and Cartesian...
Definition: SymOp.hh:28
bool is_niggli(const Eigen::Matrix3d &test_lat_mat, double compare_tol)
Check whether the given lattice (represented as a matrix) is in niggli TYPE ?? reduced form (does not...
Definition: Niggli.cc:218
void read(std::istream &stream)
Definition: Lattice.cc:116
T norm(const Tensor< T > &ttens)
Definition: Tensor.hh:968
EigenIndex Index
For long integer indexing:
Lattice canonical_equivalent_lattice(const Lattice &in_lat, const SymGroup &point_grp, double compare_tol)
Find the niggli, most standard oriented version of the given orbit (defined by the given SymGroup) of...
Definition: Niggli.cc:276
const Array< std::complex< double > >::X2 & character_table() const
Definition: SymGroup.cc:3212
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::Matrix< int, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > scale_to_int(const Eigen::MatrixBase< Derived > &val, double _tol=TOL)
Take a vector of doubles, and multiply by some factor that turns it into a vector of integers (within...
Definition: CASM_math.hh:416
Eigen::CwiseUnaryOp< decltype(std::ptr_fun(boost::math::lround< typename Derived::Scalar >)), const Derived > lround(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd to Eigen::MatrixXl.
SymOp to_canonical(double tol=TOL) const
Returns the operation that applied to *this returns the canonical form.
Definition: Lattice.cc:249
void enforce_group(double tol=TOL, Index max_size=200)
Enforce group property by adding products of operations to the group.
Definition: SymGroup.cc:3365
Lattice canonical_form(double tol=TOL) const
Returns the canonical equivalent Lattice, using the point group of the Lattice.
Definition: Lattice.cc:289
bool is_supercell_of(const Lattice &tile, Eigen::Matrix3d &multimat, double _tol=TOL) const
Matrix that relates two lattices (e.g., strain or slat)
Definition: Lattice.cc:655
SymOp inverse() const
get the inverse of this SymOp
Definition: SymOp.cc:82
Eigen::Vector3i get_millers(Eigen::Vector3d plane_normal, double tolerance=TOL) const
Given a normal vector, a Vector3 containing the miller indeces for the lattice is generated...
Definition: Lattice.cc:694
const T & min() const
Definition: Array.hh:623
Index find(const T &test_elem) const
Definition: Array.hh:707
bool is_group(double tol=TOL) const
Check to see if SymGroup satisfies the group property.
Definition: SymGroup.cc:3346
T const * end() const
Definition: Array.hh:197
double vol() const
Return signed volume of this lattice.
Definition: Lattice.hh:83
bool is_integer(const Eigen::MatrixBase< Derived > &M, double tol)
Check if Eigen::Matrix is integer.
SymOpOutputIterator find_invariant_subgroup(SymOpIterator begin, SymOpIterator end, SymOpOutputIterator result, double pg_tol=TOL) const
Output the SymOp that leave this lattice invariant.
Definition: Lattice_impl.hh:77
Lattice scaled_lattice(double scale) const
Return scaled copy of this lattice (Note: Volume will be scaled by scale^3)
Definition: Lattice.cc:87
bool operator<(const Lattice &RHS) const
Compare two Lattice.
Definition: Lattice.cc:1013
Eigen::Matrix3d Matrix3d
void nearest_rational_number(double val, long &numerator, long &denominator, double tol=TOL)
Definition: CASM_math.cc:188
Lattice get_reciprocal() const
Return reciprocal lattice.
Definition: Lattice.cc:149
virtual void push_back(const SymOp &new_op)
Definition: SymGroup.cc:441
void reserve(Index new_max)
Definition: Array.hh:491
bool is_right_handed() const
Check if the lattice is right handed.
Definition: Lattice.cc:1096
Eigen::Vector3i enclose_sphere(double radius) const
Definition: Lattice.cc:626
jsonParser & push_back(const T &value)
Puts new valued element at end of array of any type T for which 'jsonParser& to_json( const T &value...
Definition: jsonParser.hh:696
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.
double max_voronoi_measure(const Eigen::Vector3d &pos, Eigen::Vector3d &lattice_trans) const
Definition: Lattice.cc:530
void symmetrize(const SymGroup &relaxed_pg)
Force this lattice to have symmetry of group.
Definition: Lattice.cc:1038
Lattice & make_right_handed()
Flip c vector if it's on the wrong side of a-b plane – return (*this)
Definition: Lattice.cc:681
void set_lattice(const Lattice &new_lat)
Definition: SymGroup.cc:435
std::pair< bool, Eigen::MatrixXi > is_supercell(const Lattice &scel, const Lattice &unit, double tol)
Check if scel is a supercell of unitcell unit and some integer transformation matrix T...
Definition: Lattice.cc:1196
double volume(const Lattice &lat)
Returns the volume of a Lattice.
Definition: Lattice.hh:372
Array< int > calc_kpoints(Array< int > prim_kpoints, Lattice prim_lat)
Definition: Lattice.cc:161
T const * begin() const
Definition: Array.hh:185
Matrix< long int, 3, 3 > Matrix3l
const std::string & get_name() const
Definition: SymGroup.cc:3220
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.
double angle(Index i) const
Return angle between lattice vectors (*this)[(i+1)%3] and (*this)[(i+2)%3], in degrees.
Definition: Lattice.cc:99
SymOp from_canonical(double tol=TOL) const
Returns the operation that applied to the canonical form returns *this.
Definition: Lattice.cc:273
jsonParser & put_array()
Puts new empty JSON array.
Definition: jsonParser.hh:285
static Lattice fcc()
Construct FCC primitive cell of unit volume.
Definition: Lattice.cc:45
Object & apply(const Transform &f, Object &obj, Args &&...args)
Eigen::Matrix3d m_lat_mat
Definition: Lattice.hh:269
bool almost_equal(const GenericCluster< CoordType > &LHS, const GenericCluster< CoordType > &RHS, double tol)
int voronoi_number(const Eigen::Vector3d &pos) const
Definition: Lattice.cc:541
void generate_supercells(Array< Lattice > &supercell, const SymGroup &effective_pg, const ScelEnumProps &enum_props) const
Populate.
Definition: Lattice.cc:410
int round(double val)
Definition: CASM_math.cc:6