CASM  1.1.0
A Clusters Approach to Statistical Mechanics
SymInfo_stream_io.cc
Go to the documentation of this file.
2 
3 #include "boost/lexical_cast.hpp"
4 #include "casm/casm_io/Log.hh"
8 
9 namespace CASM {
10 
11 const std::string traits<symmetry_type>::name = "symmetry_type";
12 
13 const std::multimap<symmetry_type, std::vector<std::string> >
14  traits<symmetry_type>::strval = {
15  {symmetry_type::identity_op, {"identity"}},
16  {symmetry_type::mirror_op, {"mirror"}},
17  {symmetry_type::glide_op, {"glide"}},
18  {symmetry_type::rotation_op, {"rotation"}},
19  {symmetry_type::screw_op, {"screw"}},
20  {symmetry_type::inversion_op, {"inversion"}},
21  {symmetry_type::rotoinversion_op, {"rotoinversion"}},
22  {symmetry_type::invalid_op, {"invalid"}}};
23 
25 
26 void print_sym_info(Log &log, const SymInfo &info, SymInfoOptions opt) {
33  std::stringstream stream;
34  char term(0);
35  Eigen::IOFormat format(opt.prec, opt.prec + 1);
36 
37  auto print_coord = [&](const xtal::Coordinate &coord) {
38  coord.print(log, opt.coord_type, term, format);
39  };
40 
41  auto print_axis = [&](const xtal::Coordinate &coord) {
42  coord.print_axis(log, opt.coord_type, term, format);
43  };
44 
45  switch (info.op_type) {
47  log << log.indent_str() << "Identity Operation";
48  break;
49 
51  log.ostream().setf(std::ios::showpoint);
52  log << log.indent_str() << "Mirror Operation with plane normal ";
53  print_axis(info.axis);
54  break;
55 
57  stream.setf(std::ios::showpoint);
58  log << log.indent_str() << "Glide Operation with plane normal ";
59  print_axis(info.axis);
60  log << '\n';
61  log << log.indent_str() << "Glide Vector: ";
62  print_coord(info.screw_glide_shift);
63  break;
64 
66  log.ostream().unsetf(std::ios::showpoint);
67  log << log.indent_str() << std::setprecision(opt.prec) << info.angle
68  << "-degree Rotation Operation about axis ";
69  log.ostream().setf(std::ios::showpoint);
70  print_axis(info.axis);
71  break;
72 
74  log.ostream().unsetf(std::ios::showpoint);
75  log << log.indent_str() << std::setprecision(opt.prec) << info.angle
76  << "-degree Screw Operation along axis ";
77  log.ostream().setf(std::ios::showpoint);
78  log << log.indent_str() << std::setw(opt.prec + 4);
79  print_axis(info.axis);
80  log << log.indent_str() << "\n Screw Vector: ";
81  print_coord(info.screw_glide_shift);
82  break;
83 
85  log << log.indent_str() << "Inversion Operation";
86  break;
87 
89  log.ostream().unsetf(std::ios::showpoint);
90  log << log.indent_str() << std::setprecision(opt.prec) << info.angle
91  << "-degree Rotoinversion Operation about axis ";
92  log.ostream().setf(std::ios::showpoint);
93  print_axis(info.axis);
94  break;
95 
97  log << log.indent_str() << "Invalid Operation !!!";
98  break;
99  }
100 }
101 
108 std::string to_string(const SymInfo &info, SymInfoOptions opt) {
109  std::stringstream ss;
110  Log log(ss);
111  print_sym_info(log, info, opt);
112  return ss.str();
113 }
114 
115 struct PolyWriter {
116  std::stringstream ss;
118  bool add;
119 
120  PolyWriter(SymInfoOptions _opt = SymInfoOptions()) : opt(_opt), add(false) {}
121 
122  void add_constant(double val) {
123  if (!almost_zero(val, opt.tol)) {
124  if (add) {
125  if (val < 0) {
126  ss << "-";
127  val *= -1.;
128  } else {
129  ss << "+";
130  }
131  }
132  ss << std::setprecision(opt.prec) << val;
133  add = true;
134  }
135  };
136 
137  void add_term(double coeff, std::string var) {
138  if (!almost_zero(coeff, opt.tol)) {
139  if (add && coeff > 0) {
140  ss << "+";
141  } else if (coeff < 0) {
142  ss << "-";
143  coeff *= -1.;
144  }
145 
146  if (almost_equal(coeff, 1., opt.tol)) {
147  ss << var;
148  } else {
149  ss << std::setprecision(opt.prec) << coeff << "*" << var;
150  }
151  add = true;
152  }
153  };
154 
155  // normalize vectors and point in direction to make first coeff positive
156  static void standardize(Eigen::Vector3d &v, double tol = TOL) {
157  v.normalize();
158  for (int i = 0; i < 3; ++i) {
159  if (almost_zero(v(i), tol)) {
160  continue;
161  }
162  if (v(i) < 0.) {
163  v = -1. * v;
164  }
165  break;
166  }
167  };
168 };
169 
172 std::string sym_line(const xtal::Coordinate &axis,
173  const xtal::Coordinate &point, SymInfoOptions opt) {
174  std::stringstream ss;
175  double tol = opt.tol;
176 
177  Eigen::Vector3d a = axis.as_vec(opt.coord_type);
178  Eigen::Vector3d p = point.as_vec(opt.coord_type);
179 
180  // find first non-zero axis coordinate, to choose 'x', 'y', or 'z' as param
181  std::string _param = "xyz";
182  int min_i = -1;
183  for (int i = 0; i < 3; ++i) {
184  if (!almost_zero(a[i], tol)) {
185  min_i = i;
186  break;
187  }
188  }
189  std::string param = _param.substr(min_i, 1);
190 
191  PolyWriter::standardize(a, tol);
192 
193  if (opt.coord_type == FRAC) {
194  a = scale_to_int(a).cast<double>();
195  }
196 
197  // avoid lines of form '0, 1.8671, 1.2922+z' in favor of '0, 1.8671, z'
198  for (int i = 0; i < 3; ++i) {
199  if (almost_zero(a[(i + 1) % 3]) && almost_zero(a[(i + 2) % 3])) {
200  p[i] = 0.;
201  }
202  }
203 
204  for (int i = 0; i < 3; ++i) {
205  PolyWriter writer(opt);
206  writer.add_constant(p[i]);
207  writer.add_term(a[i], param);
208 
209  if (!writer.ss.str().size()) {
210  ss << 0;
211  } else {
212  ss << writer.ss.str();
213  }
214 
215  if (i != 2) {
216  ss << ", ";
217  }
218  }
219 
220  return ss.str();
221 }
222 
225 std::string sym_plane(const xtal::Coordinate &v1, const xtal::Coordinate &v2,
226  const xtal::Coordinate &point, SymInfoOptions opt) {
227  std::stringstream ss;
228  double tol = opt.tol;
229 
230  Eigen::Vector3d a = v1.as_vec(opt.coord_type);
231  Eigen::Vector3d b = v2.as_vec(opt.coord_type);
232  Eigen::Vector3d p = point.as_vec(opt.coord_type);
233 
234  // in most cases, having 'a*x+b*y' in the same term can be avoided,
235  // but in some cases it is impossible:
236  // ex: in primitive fcc, the mirror plane: '2*x, 2*y, -x-y'
237  //
238  // here we mostly avoid such representations
239  // and situations 'x' is used for 'a' and neither 'y' or 'z' can be used for
240  // 'b'
241  //
242  for (int i = 0; i < 3; ++i) {
243  if (!almost_zero(a[i], tol) && !almost_zero(b[i], tol)) {
244  b = b - b[i] / a[i] * a;
245  break;
246  }
247  }
248 
249  for (int i = 0; i < 3; ++i) {
250  if (!almost_zero(a[i], tol) && !almost_zero(b[i], tol)) {
251  a = a - a[i] / b[i] * b;
252  break;
253  }
254  }
255 
256  // find first non-zero axis coordinate, to choose 'x', 'y', or 'z' as param
257  std::string _param = "xyz";
258  int min_i = -1;
259  for (int i = 0; i < 3; ++i) {
260  if (!almost_zero(a[i], tol)) {
261  min_i = i;
262  break;
263  }
264  }
265  int min_j = -1;
266  for (int j = 0; j < 3; ++j) {
267  if (!almost_zero(b[j], tol) && j != min_i) {
268  min_j = j;
269  break;
270  }
271  }
272 
273  if (min_i == -1 || min_j == -1) {
274  std::stringstream msg;
275  msg << "Unexpected error in sym_plane: Could not write a description for "
276  "the symmetry plane defined by a: "
277  << a.transpose() << ", b: " << b.transpose()
278  << ", p: " << p.transpose();
279  throw std::runtime_error(msg.str());
280  }
281 
282  // associate lesser of 'x','y','z' with 'a'
283  if (min_j < min_i) {
284  using std::swap;
285  swap(a, b);
286  swap(min_j, min_i);
287  }
288 
289  std::string param1 = _param.substr(min_i, 1);
290  std::string param2 = _param.substr(min_j, 1);
291 
292  if (opt.coord_type == FRAC) {
293  PolyWriter::standardize(a, tol);
294  PolyWriter::standardize(b, tol);
295 
296  // fractional coords can be scaled to int
297  a = scale_to_int(a).cast<double>();
298  b = scale_to_int(b).cast<double>();
299  }
300 
301  // p + a*x + b*y, where p is a constant point,
302  // a, b are vectors of coeffs, and param1 and param2 are variable names
303  for (int i = 0; i < 3; ++i) {
304  PolyWriter writer(opt);
305  writer.add_constant(p[i]);
306  writer.add_term(a[i], param1);
307  writer.add_term(b[i], param2);
308 
309  if (!writer.ss.str().size()) {
310  ss << 0;
311  } else {
312  ss << writer.ss.str();
313  }
314 
315  if (i != 2) {
316  ss << ", ";
317  }
318  }
319 
320  return ss.str();
321 }
322 
325 std::string sym_plane(const xtal::Coordinate &axis,
326  const xtal::Coordinate &point, SymInfoOptions opt) {
327  double tol = opt.tol;
328 
329  Eigen::Vector3d n = axis.const_cart();
330  Eigen::Vector3d _v1;
331  Eigen::Vector3d _v2;
332  n.normalize();
333 
334  // get first vector orthogonal to axis
335  if (!almost_equal(std::abs(n(0)), 1., tol)) {
336  Eigen::Vector3d x;
337  x << 1., 0., 0.;
338  _v1 = x - x.dot(n) * n;
339  } else {
340  Eigen::Vector3d y;
341  y << 0., 1., 0.;
342  _v1 = y - y.dot(n) * n;
343  }
344  PolyWriter::standardize(_v1, tol);
345 
346  // get second vector in symmetry plane
347  _v2 = _v1.cross(n);
348  PolyWriter::standardize(_v2, tol);
349 
350  // use plane defining vectors and invariant point to write the plane equation
351  xtal::Coordinate v1(_v1, axis.home(), CART);
352  xtal::Coordinate v2(_v2, axis.home(), CART);
353  return sym_plane(v1, v2, point, opt);
354 }
355 
364 std::string to_brief_unicode(const SymInfo &info, SymInfoOptions opt) {
365  std::stringstream stream;
366  char term(0);
367  stream.flags(std::ios::showpoint | std::ios::fixed | std::ios::right);
368  Eigen::IOFormat format(opt.prec, opt.prec + 1);
369 
370  // print rotation or screw integer, and include trailing space
371  auto print_r = [&](bool inversion) {
372  int r = std::lround(360. / std::min(info.angle, 360. - info.angle));
373  if (r == 2) {
374  if (inversion) stream << "-";
375  stream << boost::lexical_cast<std::string>(r);
376  } else if (info.angle < 180.) {
377  if (inversion) stream << "-";
378  stream << boost::lexical_cast<std::string>(r);
379  // add superscript '+'
380  stream << "\u207A";
381  } else {
382  if (inversion) stream << "-";
383  stream << boost::lexical_cast<std::string>(r);
384  // add superscript '-'
385  stream << "\u207B";
386  }
387  if (info.time_reversal) stream << "\u2032";
388  stream << " ";
389  };
390 
391  auto print_coord = [&](const xtal::Coordinate &coord) {
392  coord.print(stream, opt.coord_type, term, format);
393  };
394 
395  switch (info.op_type) {
397  stream << "1";
398  if (info.time_reversal) stream << "\u2032";
399  break;
400 
402  stream.setf(std::ios::showpoint);
403  stream << "m";
404  if (info.time_reversal) stream << "\u2032";
405  stream << " ";
406  stream << sym_plane(info.axis, info.location, opt);
407  break;
408 
410  stream.setf(std::ios::showpoint);
411  stream << "g";
412  if (info.time_reversal) stream << "\u2032";
413  stream << " (";
414  print_coord(info.screw_glide_shift); // glide shift
415  stream << ") ";
416  stream << sym_plane(info.axis, info.location, opt);
417  break;
418 
420  print_r(false);
421  stream << sym_line(info.axis, info.location, opt);
422  break;
423 
425  print_r(false);
426  stream << "(";
427  print_coord(info.screw_glide_shift); // screw shift
428  stream << ") " << sym_line(info.axis, info.location, opt);
429  break;
430 
432  stream << "-1";
433  if (info.time_reversal) stream << "\u2032";
434  stream << " ";
435  print_coord(info.location); // inversion point
436  break;
437 
439  print_r(true);
440  stream << sym_line(info.axis, info.location, opt);
441  stream << "; ";
442  print_coord(info.location); // invariant point
443  break;
444 
446  stream << "<error invalid>";
447  break;
448  }
449 
450  return stream.str();
451 }
452 
454 std::string description(const SymOp &op, const xtal::Lattice &lat,
455  SymInfoOptions opt) {
456  return to_string(SymInfo(op, lat), opt);
457 }
458 
462 void description(Log &log, const SymGroup &g, const xtal::Lattice &lat,
463  SymInfoOptions opt) {
464  bool print_master_index = false;
465  Index i = 0;
466  for (const auto &op : g) {
467  if (op.has_valid_master() && i != op.index()) {
468  print_master_index = true;
469  continue;
470  }
471  ++i;
472  }
473 
474  i = 1;
475  for (const auto &op : g) {
476  log << log.indent_str() << i;
477  if (print_master_index) {
478  log << " (" << op.index() + 1 << ")";
479  }
480  log << ": " << description(op, lat, opt) << std::endl;
481  if (opt.print_matrix_tau) {
482  print_matrix_tau_col(log, op, opt.prec);
483  }
484  ++i;
485  }
486 }
487 
489 std::string brief_description(const SymOp &op, const xtal::Lattice &lat,
490  SymInfoOptions opt) {
491  return to_brief_unicode(SymInfo(op, lat), opt);
492 }
493 
501 void brief_description(Log &log, const SymGroup &g, const xtal::Lattice &lat,
502  SymInfoOptions opt) {
503  bool print_master_index = false;
504  Index i = 0;
505  for (const auto &op : g) {
506  if (op.has_valid_master() && i != op.index()) {
507  print_master_index = true;
508  continue;
509  }
510  ++i;
511  }
512 
513  i = 1;
514  for (const auto &op : g) {
515  log << log.indent_str() << i;
516  if (print_master_index) {
517  log << " (" << op.index() + 1 << ")";
518  }
519  log << ": " << brief_description(op, lat, opt) << std::endl;
520  if (opt.print_matrix_tau) {
521  print_matrix_tau_col(log, op, opt.prec);
522  }
523  ++i;
524  }
525 }
526 
527 } // namespace CASM
#define ENUM_IO_DEF(ENUM)
Definition: stream_io.hh:13
Definition: Log.hh:48
std::string indent_str() const
Definition: Log.hh:273
std::ostream & ostream()
Definition: Log.hh:262
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 Lattice & home() const
Access the home lattice of the coordinate.
Definition: Coordinate.hh:200
vector_type as_vec(COORD_TYPE _mode) const
Definition: Coordinate.hh:103
const vector_type & const_cart() const
user override to force const Access the Cartesian coordinate vector
Definition: Coordinate.hh:90
std::string to_string(ENUM val)
Return string representation of enum class.
Definition: io_traits.hh:172
Eigen::CwiseUnaryOp< decltype(Local::lround_l< typename Derived::Scalar >), const Derived > lround(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd to Eigen::MatrixXl.
void print_matrix_tau_col(Log &log, const SymOp &op, Index prec)
Print formatted SymOp matrix and tau.
Definition: SymOp.cc:196
symmetry_type
Definition: SymInfo.hh:14
GenericDatumFormatter< std::string, ConfigEnumDataType > name()
Main CASM namespace.
Definition: APICommand.hh:8
bool almost_equal(ClusterInvariants const &A, ClusterInvariants const &B, double tol)
Check if ClusterInvariants are equal.
std::string to_brief_unicode(const SymInfo &info, SymInfoOptions opt=SymInfoOptions())
Print symmetry symbol to string.
std::string description(const SymOp &op, const xtal::Lattice &lat, SymInfoOptions opt=SymInfoOptions())
Print SymInfo to string.
Log & log()
Definition: Log.hh:424
std::string brief_description(const SymOp &op, const xtal::Lattice &lat, SymInfoOptions opt=SymInfoOptions())
Print SymInfo to brief string.
void swap(ConfigDoF &A, ConfigDoF &B)
Definition: ConfigDoF.cc:260
const COORD_TYPE FRAC
Definition: enum.hh:8
const double TOL
Definition: definitions.hh:30
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:104
std::string sym_line(const xtal::Coordinate &axis, const xtal::Coordinate &point, SymInfoOptions opt)
Use axis and invariant point to return line in '0, y, 0'-type notation.
T min(const T &A, const T &B)
Definition: CASM_math.hh:88
void print_sym_info(Log &log, const SymInfo &info, SymInfoOptions opt=SymInfoOptions())
Print SymInfo.
const COORD_TYPE CART
Definition: enum.hh:9
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
std::string sym_plane(const xtal::Coordinate &v1, const xtal::Coordinate &v2, const xtal::Coordinate &point, SymInfoOptions opt)
Use two perpendicular vectors in plane and invariant point to return plane in 'x, y,...
Eigen::Matrix< int, Derived::RowsAtCompileTime, Derived::ColsAtCompileTime > scale_to_int(const Eigen::MatrixBase< Derived > &val, double _tol=CASM::TOL)
std::stringstream ss
void add_term(double coeff, std::string var)
SymInfoOptions opt
PolyWriter(SymInfoOptions _opt=SymInfoOptions())
void add_constant(double val)
static void standardize(Eigen::Vector3d &v, double tol=TOL)
Simple struct to be used as return type for SymOp::info().
Definition: SymInfo.hh:26
double angle
Definition: SymInfo.hh:42
xtal::Coordinate axis
Definition: SymInfo.hh:38
symmetry_type op_type
Definition: SymInfo.hh:31
xtal::Coordinate screw_glide_shift
Definition: SymInfo.hh:46
xtal::Coordinate location
A Cartesian coordinate that is invariant to the operation (if one exists)
Definition: SymInfo.hh:49
bool time_reversal
If time reversal symmetry.
Definition: SymInfo.hh:52
Options for printing SymInfo.