CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
BasicStructure_impl.hh
Go to the documentation of this file.
1 #include <sstream>
2 #include <string>
3 #include <sys/stat.h>
4 #include <sys/types.h>
5 
13 
14 namespace CASM {
15  template<typename CoordType>
16  BasicStructure<CoordType>::BasicStructure(const fs::path &filepath) : m_lattice() {
17  if(!fs::exists(filepath)) {
18  std::cout << "Error in BasicStructure<CoordType>::BasicStructure<CoordType>(const fs::path &filepath)." << std::endl;
19  std::cout << " File does not exist at: " << filepath << std::endl;
20  exit(1);
21  }
22  fs::ifstream infile(filepath);
23 
24  read(infile);
25  }
26 
27  //***********************************************************
28 
29  template<typename CoordType>
31  m_lattice(RHS.lattice()), title(RHS.title), basis(RHS.basis) {
32  for(Index i = 0; i < basis.size(); i++) {
33  basis[i].set_lattice(lattice(), CART);
34  }
35  }
36 
37  //***********************************************************
38 
39  template<typename CoordType>
41  m_lattice = RHS.lattice();
42  title = RHS.title;
43  basis = RHS.basis;
44  for(Index i = 0; i < basis.size(); i++) {
45  basis[i].set_lattice(lattice(), CART);
46  }
47 
48  return *this;
49  }
50 
51 
52  //***********************************************************
53 
54  template<typename CoordType>
56 
57  }
58 
59  //***********************************************************
60  /*
61  template<typename CoordType>
62  BasicStructure<CoordType> &BasicStructure<CoordType>::apply_sym(const SymOp &op) {
63  for(Index i = 0; i < basis.size(); i++) {
64  basis[i].apply_sym(op);
65  }
66  return *this;
67  }
68  */
69  //***********************************************************
70 
71  template<typename CoordType>
73 
74 
75  for(Index nb = 0; nb < basis.size(); nb++) {
76  basis[nb].set_basis_ind(nb);
77  }
78  within();
79  //set_site_internals();
80 
81  }
82 
83  //***********************************************************
84 
85  template<typename CoordType>
87  set_site_internals();
88  }
89 
90  //***********************************************************
91 
92  template<typename CoordType>
94  for(Index i = 0; i < basis.size(); i++) {
95  basis[i].within();
96  }
97  return;
98  }
99 
100  //***********************************************************
101 
102  template<typename CoordType>
103  void BasicStructure<CoordType>::generate_factor_group_slow(SymGroup &factor_group, double map_tol) const {
104  //std::cout << "SLOW GENERATION OF FACTOR GROUP " << &factor_group << "\n";
105  //std::cout << "begin generate_factor_group_slow() " << this << std::endl;
106 
107  Array<CoordType> trans_basis;
108  Index pg, b0, b1, b2;
109  Coordinate t_tau(lattice());
110  Index num_suc_maps;
111 
112  SymGroup point_group;
113  //reset();
114  lattice().generate_point_group(point_group, map_tol);
115 
116  if(factor_group.size() != 0) {
117  std::cerr << "WARNING in BasicStructure<CoordType>::generate_factor_group_slow" << std::endl;
118  std::cerr << "The factor group passed isn't empty and it's about to be rewritten!" << std::endl;
119  factor_group.clear();
120  }
121  factor_group.set_lattice(lattice());
122  //Loop over all point group ops of the lattice
123  for(pg = 0; pg < point_group.size(); pg++) {
124  trans_basis.clear();
125  //First, generate the symmetrically transformed basis sites
126  //Loop over all sites in basis
127  for(b0 = 0; b0 < basis.size(); b0++) {
128  trans_basis.push_back(point_group[pg]*basis[b0]);
129  }
130 
131  //Using the symmetrically transformed basis, find all possible translations
132  //that MIGHT map the symmetrically transformed basis onto the original basis
133  for(b0 = 0; b0 < trans_basis.size(); b0++) {
134 
135  if(!basis[0].compare_type(trans_basis[b0]))
136  continue;
137 
138  t_tau = basis[0] - trans_basis[b0];
139 
140  t_tau.within();
141  num_suc_maps = 0; //Keeps track of number of old->new basis site mappings that are found
142 
143  double tdist = 0.0;
144  double max_error = 0.0;
145  for(b1 = 0; b1 < basis.size(); b1++) { //Loop over original basis sites
146  for(b2 = 0; b2 < trans_basis.size(); b2++) { //Loop over symmetrically transformed basis sites
147 
148  //see if translation successfully maps the two sites
149  if(basis[b1].compare(trans_basis[b2], t_tau, map_tol)) {
150  tdist = basis[b1].min_dist(Coordinate(trans_basis[b2]) + t_tau);
151  if(tdist > max_error) {
152  max_error = tdist;
153  }
154  num_suc_maps++;
155  break;
156  }
157  }
158 
159  //break out of outer loop if inner loop finds no successful map
160  if(b2 == trans_basis.size()) {
161  break;
162  }
163  }
164 
165  //If all atoms in the basis are mapped successfully, try to add the corresponding
166  //symmetry operation to the factor_group
167  if(num_suc_maps == basis.size()) {
168  SymOp tSym(SymOp::translation(t_tau.cart())*point_group[pg]);
169  tSym.set_map_error(max_error);
170 
171  if(!factor_group.contains(tSym)) {
172  factor_group.push_back(tSym);
173  }
174  }
175  }
176  } //End loop over point_group operations
177  factor_group.enforce_group(map_tol);
178  factor_group.sort();
179  factor_group.max_error();
180 
181  //std::cout << "finish generate_factor_group_slow() " << this << std::endl;
182  return;
183  }
184 
185  //************************************************************
186 
187  template<typename CoordType>
188  void BasicStructure<CoordType>::generate_factor_group(SymGroup &factor_group, double map_tol) const {
189  //std::cout << "begin generate_factor_group() " << this << std::endl;
191  factor_group.clear();
192  factor_group.set_lattice(lattice());
193  // CASE 1: Structure is primitive
194  if(is_primitive(tprim, map_tol)) {
195  generate_factor_group_slow(factor_group, map_tol);
196  return;
197  }
198 
199 
200  // CASE 2: Structure is not primitive
201 
202  PrimGrid prim_grid(tprim.lattice(), lattice());
203  //std::cout << "FAST GENERATION OF FACTOR GROUP " << &factor_group << " FOR STRUCTURE OF VOLUME " << prim_grid.size() << "\n";
204 
205  SymGroup prim_fg;
206  tprim.generate_factor_group_slow(prim_fg, map_tol);
207 
208  SymGroup point_group;
209  lattice().generate_point_group(point_group, map_tol);
210  point_group.enforce_group(map_tol);
211 
212  for(Index i = 0; i < prim_fg.size(); i++) {
213  if(point_group.find_no_trans(prim_fg[i]) == point_group.size()) {
214  continue;
215  }
216  else {
217  for(Index j = 0; j < prim_grid.size(); j++) {
218  factor_group.push_back(SymOp::translation(prim_grid.coord(j, SCEL).cart())*prim_fg[i]);
219  // set lattice, in case SymOp::operator* ever changes
220  }
221  }
222  }
223 
224  return;
225  }
226 
227  //************************************************************
228 
229  template<typename CoordType>
230  void BasicStructure<CoordType>::fg_converge(double small_tol, double large_tol, double increment) {
231  SymGroup factor_group;
232  fg_converge(factor_group, small_tol, large_tol, increment);
233  }
234 
235  //************************************************************
236 
237  template<typename CoordType>
238  void BasicStructure<CoordType>::fg_converge(SymGroup &factor_group, double small_tol, double large_tol, double increment) {
239 
240  Array<double> tols;
241  Array<bool> is_group;
242  Array<int> num_ops, num_enforced_ops;
243  Array<std::string> name;
244 
245  for(double i = small_tol; i < large_tol; i += increment) {
246  tols.push_back(i);
247  factor_group.clear();
248  generate_factor_group(factor_group, i);
249  factor_group.get_multi_table();
250  num_ops.push_back(factor_group.size());
251  is_group.push_back(factor_group.is_group(i));
252  factor_group.enforce_group(i);
253  num_enforced_ops.push_back(factor_group.size());
254  factor_group.character_table();
255  name.push_back(factor_group.get_name());
256  }
257 
258  for(Index i = 0; i < tols.size(); i++) {
259  std::cout << tols[i] << "\t" << num_ops[i] << "\t" << is_group[i] << "\t" << num_enforced_ops[i] << "\t name: " << name[i] << "\n";
260  }
261 
262  return;
263  }
264 
265  //***********************************************************
266 
267  //This function gets the permutation representation of the
268  // factor group operations of the structure. It first applies
269  // the factor group operation to the structure, and then tries
270  // to map the new position of the basis atom to the various positions
271  // before symmetry was applied. It only checks the positions after
272  // it brings the basis within the crystal.
273 
274  template<typename CoordType>
276 
277  if(factor_group.size() <= 0 || !basis.size()) {
278  std::cerr << "ERROR in BasicStructure::generate_basis_permutation_representation" << std::endl;
279  std::cerr << "You have NOT generated the factor group, or something is very wrong with your structure. I'm quitting!" << std::endl;;
280  exit(1);
281  }
282 
283  SymGroupRep basis_permute_group(factor_group);
284  SymGroupRepID rep_id;
285 
286  std::string clr(100, ' ');
287 
288  for(Index ng = 0; ng < factor_group.size(); ng++) {
289  if(verbose) {
290  if(ng % 100 == 0)
291  std::cout << '\r' << clr.c_str() << '\r' << "Find permute rep for symOp " << ng << "/" << factor_group.size() << std::flush;
292  }
293 
294  basis_permute_group.set_rep(ng, SymBasisPermute(factor_group[ng], *this, TOL));
295  }
296  // Adds the representation into the master sym group of this structure and returns the rep id
297  rep_id = factor_group.add_representation(basis_permute_group);
298 
299  //std::cerr << "Added basis permutation rep id " << rep_id << '\n';
300 
301  if(verbose) std::cout << '\r' << clr.c_str() << '\r' << std::flush;
302  return rep_id;
303  }
304 
305 
306  //***********************************************************
319  //***********************************************************
320 
321  template<typename CoordType>
323  Index i, j;
324 
325  copy_attributes_from(prim);
326 
327  PrimGrid prim_grid(prim.lattice(), lattice());
328 
329  basis.clear();
330 
331  //loop over basis sites of prim
332  for(j = 0; j < prim.basis.size(); j++) {
333 
334  //loop over prim_grid points
335  for(i = 0; i < prim_grid.size(); i++) {
336 
337  //push back translated basis site of prim onto superstructure basis
338  basis.push_back(prim.basis[j] + prim_grid.coord(i, PRIM));
339 
340  //reset lattice for most recent superstructure CoordType
341  //set_lattice() converts fractional coordinates to be compatible with new lattice
342  basis.back().set_lattice(lattice(), CART);
343 
344  basis.back().within();
345  }
346  }
347 
348  set_site_internals();
349 
350  return;
351  }
352 
353  //***********************************************************
362  //***********************************************************
363 
364  template<typename CoordType>
366  BasicStructure<CoordType> tsuper(scel_lat);
367  tsuper.fill_supercell(*this);
368  return tsuper;
369  }
370 
371 
372  //***********************************************************
376  //***********************************************************
377 
378  template<typename CoordType>
379  bool BasicStructure<CoordType>::is_primitive(double prim_tol) const {
380  Coordinate tshift(lattice());//, bshift(lattice);
381  Index b1, b2, b3, num_suc_maps;
382 
383  for(b1 = 1; b1 < basis.size(); b1++) {
384  if(!basis[0].compare_type(basis[b1])) {
385  continue;
386  }
387 
388  tshift = basis[0] - basis[b1];
389  num_suc_maps = 0;
390  for(b2 = 0; b2 < basis.size(); b2++) {
391  for(b3 = 0; b3 < basis.size(); b3++) {
392  //if(basis[b3].compare_type(basis[b2], bshift) && tshift.min_dist(bshift) < prim_tol) {
393  if(basis[b3].compare(basis[b2], tshift, prim_tol)) {
394  num_suc_maps++;
395  break;
396  }
397  }
398  if(b3 == basis.size()) {
399  break;
400  }
401  }
402 
403  if(num_suc_maps == basis.size()) {
404  return false;
405  }
406 
407  }
408 
409  return true;
410  }
411 
412 
413  //***********************************************************
418  //***********************************************************
419 
420  template<typename CoordType>
422  Coordinate tshift(lattice());//, bshift(lattice);
423  Eigen::Vector3d prim_vec0(lattice()[0]), prim_vec1(lattice()[1]), prim_vec2(lattice()[2]);
425  Index b1, b2, b3, sh, sh1, sh2;
426  Index num_suc_maps;
427  double tvol, min_vol;
428  bool prim_flag = true;
429  double prim_vol_tol = std::abs(0.5 * lattice().vol() / double(basis.size())); //sets a hard lower bound for the minimum value of the volume of the primitive cell
430 
431  for(b1 = 1; b1 < basis.size(); b1++) {
432  tshift = basis[0] - basis[b1];
433  if(almost_zero(tshift.min_dist(Coordinate::origin(lattice()))))
434  continue;
435  num_suc_maps = 0;
436  for(b2 = 0; b2 < basis.size(); b2++) {
437  for(b3 = 0; b3 < basis.size(); b3++) {
438  if(basis[b3].compare(basis[b2], tshift, prim_tol)) {
439  num_suc_maps++;
440  break;
441  }
442  }
443  if(b3 == basis.size()) {
444  break;
445  }
446  }
447  if(num_suc_maps == basis.size()) {
448  prim_flag = false;
449  shift.push_back(tshift.cart());
450  }
451  }
452 
453  if(prim_flag) {
454  new_prim = (*this);
455  return true;
456  }
457 
458  shift.push_back(lattice()[0]);
459  shift.push_back(lattice()[1]);
460  shift.push_back(lattice()[2]);
461 
462  //We want to minimize the volume of the primitivized cell, but to make it not a weird shape
463  //that leads to noise we also minimize the dot products like get_reduced cell would
464  min_vol = std::abs(lattice().vol());
465  for(sh = 0; sh < shift.size(); sh++) {
466  for(sh1 = sh + 1; sh1 < shift.size(); sh1++) {
467  for(sh2 = sh1 + 1; sh2 < shift.size(); sh2++) {
468  tvol = std::abs(triple_prod(shift[sh], shift[sh1], shift[sh2]));
469  if(tvol < min_vol && tvol > prim_vol_tol) {
470  min_vol = tvol;
471  prim_vec0 = shift[sh];
472  prim_vec1 = shift[sh1];
473  prim_vec2 = shift[sh2];
474  }
475  }
476  }
477 
478  }
479 
480 
481  Lattice new_lat(prim_vec0, prim_vec1, prim_vec2);
482  Lattice reduced_new_lat = niggli(new_lat, prim_tol);
483 
484  //The lattice so far is OK, but it's noisy enough to matter for large
485  //superstructures. We eliminate the noise by reconstructing it now via
486  //rounded to integer transformation matrix.
487 
488  Eigen::Matrix3d transmat, invtransmat, reduced_new_lat_mat;
489  SymGroup pgroup;
490  reduced_new_lat.generate_point_group(pgroup, prim_tol);
491 
492  //Do not check to see if it returned true, it very well may not!
493  lattice().is_supercell_of(reduced_new_lat, pgroup, transmat);
494 
495  //Round transformation elements to integers
496  for(int i = 0; i < 3; i++) {
497  for(int j = 0; j < 3; j++) {
498  transmat(i, j) = floor(transmat(i, j) + 0.5);
499  }
500  }
501 
502  invtransmat = transmat.inverse();
503  reduced_new_lat_mat = lattice().lat_column_mat();
504  //When constructing this, why are we using *this as the primitive cell? Seems like I should only specify the vectors
505  Lattice reconstructed_reduced_new_lat(reduced_new_lat_mat * invtransmat);
506  reconstructed_reduced_new_lat.make_right_handed();
507  //Lattice reconstructed_reduced_new_lat(reduced_new_lat_mat*invtransmat,lattice);
508 
509  new_prim.set_lattice(reconstructed_reduced_new_lat, CART);
510  CoordType tsite(new_prim.lattice());
511  for(Index nb = 0; nb < basis.size(); nb++) {
512  tsite = basis[nb];
513  tsite.set_lattice(new_prim.lattice(), CART);
514  if(new_prim.find(tsite, prim_tol) == new_prim.basis.size()) {
515  tsite.within();
516  new_prim.basis.push_back(tsite);
517  }
518  }
519 
520  //std::cout<<"%%%%%%%%%%%%%%%%"<<std::endl;
521  //std::cout<<"new_lat"<<std::endl;
522  //new_lat.print(std::cout);
523  //std::cout<<"reduced_new_lat"<<std::endl;
524  //reduced_new_lat.print(std::cout);
525  //std::cout<<"reconstructed_reduced_new_lat"<<std::endl;
526  //reconstructed_reduced_new_lat.print(std::cout);
527  //std::cout<<"transmat (rounded)"<<std::endl;
528  //std::cout<<transmat<<std::endl;
529  //std::cout<<"%%%%%%%%%%%%%%%%"<<std::endl;
530  return false;
531  }
532 
533  //***********************************************************
534 
535  template<typename CoordType>
537  //std::cout << "begin set_site_internals() " << this << std::endl;
538  Index nb;
539 
540 
541  for(nb = 0; nb < basis.size(); nb++) {
542  basis[nb].set_basis_ind(nb);
543  }
544 
545  }
546 
547  //*********************************************************
548 
549  template<typename CoordType>
551 
552  int prim_to_scel = -1;
553  CoordType shifted_site(prim.lattice());
554 
555  //Check that (*this) is actually a supercell of the prim
556  if(!lattice().is_supercell_of(prim.lattice(), point_group)) {
557  std::cout << "*******************************************\n"
558  << "ERROR in BasicStructure<CoordType>::map_superstruc_to_prim:\n"
559  << "The structure \n";
560  //print(std::cout);
561  std::cout << jsonParser(*this) << std::endl;
562  std::cout << "is not a supercell of the given prim!\n";
563  //prim.print(std::cout);
564  std::cout << jsonParser(prim) << std::endl;
565  std::cout << "*******************************************\n";
566  exit(1);
567  }
568 
569  //Get prim grid of supercell to get the lattice translations
570  //necessary to stamp the prim in the superstructure
571  PrimGrid prim_grid(prim.lattice(), lattice());
572 
573  // Translate each of the prim atoms by prim_grid translation
574  // vectors, and map that translated atom in the supercell.
575  for(Index pg = 0; pg < prim_grid.size(); pg++) {
576  for(Index pb = 0; pb < prim.basis.size(); pb++) {
577  shifted_site = prim.basis[pb];
578  //shifted_site lattice is PRIM, so get prim_grid.coord in PRIM mode
579  shifted_site += prim_grid.coord(pg, PRIM);
580  shifted_site.set_lattice(lattice(), CART);
581  shifted_site.within();
582 
583  // invalidate asym_ind and basis_ind because when we use
584  // BasicStructure<CoordType>::find, we don't want a comparison using the
585  // basis_ind and asym_ind; we want a comparison using the
586  // cartesian and Specie type.
587 
588  shifted_site.set_basis_ind(-1);
589  prim_to_scel = find(shifted_site);
590 
591  if(prim_to_scel == basis.size()) {
592  std::cout << "*******************************************\n"
593  << "ERROR in BasicStructure<CoordType>::map_superstruc_to_prim:\n"
594  << "Cannot associate site \n"
595  << shifted_site << "\n"
596  << "with a site in the supercell basis. \n"
597  << "*******************************************\n";
598  std::cout << "The basis_ind and asym_ind are "
599  << shifted_site.basis_ind() << "\t "
600  << shifted_site.asym_ind() << "\n";
601  exit(2);
602  }
603 
604  // Set ind_to_prim of the basis site
605  basis[prim_to_scel].ind_to_prim = pb;
606  }
607  }
608  }
609 
610  //***********************************************************
611 
612  template<typename CoordType> template<typename CoordType2>
613  Index BasicStructure<CoordType>::find(const CoordType2 &test_site, double tol) const {
614  for(Index i = 0; i < basis.size(); i++) {
615  if(basis[i].compare(test_site, tol)) {
616  return i;
617  }
618  }
619  return basis.size();
620  }
621 
622  //***********************************************************
623 
624  template<typename CoordType> template<typename CoordType2>
625  Index BasicStructure<CoordType>::find(const CoordType2 &test_site, const Coordinate &shift, double tol) const {
626  for(Index i = 0; i < basis.size(); i++) {
627  if(basis[i].compare(test_site, shift, tol)) {
628  return i;
629  }
630  }
631  return basis.size();
632  }
633 
634  //John G 070713
635  //***********************************************************
643  //***********************************************************
644 
645  template<typename CoordType> template<typename CoordType2>
646  UnitCellCoord BasicStructure<CoordType>::get_unit_cell_coord(const CoordType2 &bsite, double tol) const {
647 
648  CoordType2 tsite = bsite;
649 
650  tsite.set_lattice(lattice(), CART);
651 
652  Index b;
653 
654  b = find(tsite, tol);
655 
656  if(b == basis.size()) {
657  std::cerr << "ERROR in BasicStructure::get_unit_cell_coord" << std::endl
658  << "Could not find a matching basis site." << std::endl
659  << " Looking for: FRAC: " << tsite.const_frac() << "\n"
660  << " CART: " << tsite.const_cart() << "\n";
661  exit(1);
662  }
663 
664  return UnitCellCoord(b, lround(tsite.const_frac() - basis[b].const_frac()));
665  };
666 
667 
668  //*******************************************************************************************
669 
670  template<typename CoordType>
672  if(ucc[0] < 0 || ucc[0] >= basis.size()) {
673  std::cerr << "CRITICAL ERROR: In BasicStructure<CoordType>::get_site(), UnitCellCoord " << ucc << " is out of bounds!\n"
674  << " Cannot index basis, which contains " << basis.size() << " objects.\n";
675  assert(0);
676  exit(1);
677  }
678  Coordinate trans(Eigen::Vector3d(ucc[1], ucc[2], ucc[3]), lattice(), FRAC);
679  return basis[ucc[0]] + trans;
680  }
681 
682  //***********************************************************
683 
684  template<typename CoordType>
686 
687  m_lattice = new_lat;
688 
689  for(Index nb = 0; nb < basis.size(); nb++) {
690  basis[nb].set_lattice(lattice(), mode);
691  }
692  }
693 
694  //\Liz D 032514
695  //***********************************************************
700  //***********************************************************
701 
702 
703  template<typename CoordType>
705  basis = basis_in;
706  set_site_internals();
707  }
708 
709 
710  //\John G 121212
711  //***********************************************************
720  //***********************************************************
721  /*
722  template<typename CoordType>
723  Array<Array<Array<double> > > BasicStructure<CoordType>::get_NN_table(const double &maxr, GenericOrbitree<GenericCluster<CoordType> > &bouquet) {
724  if(!bouquet.size()) {
725  std::cerr << "WARNING in BasicStructure<CoordType>::get_NN_table" << std::endl;
726  std::cerr << "The provided GenericOrbitree<Cluster<CoordType> > is about to be rewritten!" << std::endl;
727  }
728 
729  Array<Array<Array<double> > > NN;
730  GenericOrbitree<GenericCluster<CoordType> > normtree(lattice());
731  GenericOrbitree<GenericCluster<CoordType> > tbouquet(lattice());
732  bouquet = tbouquet;
733  normtree.min_num_components = 1;
734  normtree.max_num_sites = 2;
735  normtree.max_length.push_back(0.0);
736  normtree.max_length.push_back(0.0);
737  normtree.max_length.push_back(maxr);
738 
739  normtree.generate_orbitree(*this);
740  normtree.print_full_clust(std::cout);
741  generate_basis_bouquet(normtree, bouquet, 2);
742 
743  Array<Array<double> > oneNN;
744  oneNN.resize(2);
745  for(Index i = 0; i < bouquet.size(); i++) {
746  NN.push_back(oneNN);
747  for(Index j = 0; j < bouquet[i].size(); j++) {
748  NN[i][0].push_back(bouquet[i][j].size());
749  NN[i][1].push_back(bouquet[i][j].max_length());
750  }
751  }
752  return NN;
753  }
754  */
755  //***********************************************************
763  //***********************************************************
764  /*
765  template<typename CoordType>
766  Array<Array<Array<double> > > BasicStructure<CoordType>::get_NN_table(const double &maxr) {
767  GenericOrbitree<GenericCluster<CoordType> > bouquet(lattice());
768  return get_NN_table(maxr, bouquet);
769  }
770  */
771 
772  //***********************************************************
779  //***********************************************************
780 
781  template<typename CoordType>
782  void BasicStructure<CoordType>::symmetrize(const SymGroup &relaxed_factors) {
783  //First make a copy of your current basis
784  //This copy will eventually become the new average basis.
785  Array<CoordType> avg_basis = basis;
786 
787  //Loop through given symmetry group an fill a temporary "operated basis"
788  Array<CoordType> operbasis;
789 
790  //assume identity comes first, so we skip it
791  for(Index rf = 0; rf < relaxed_factors.size(); rf++) {
792  operbasis.clear();
793  for(Index b = 0; b < basis.size(); b++) {
794  operbasis.push_back(relaxed_factors[rf]*basis[b]);
795  operbasis.back().print(std::cout);
796  std::cout << std::endl;
797  }
798  //Now that you have a transformed basis, find the closest mapping of atoms
799  //Then average the distance and add it to the average basis
800  for(Index b = 0; b < basis.size(); b++) {
801  double smallest = 1000000;
802  Coordinate bshift(lattice()), tshift(lattice());
803  for(Index ob = 0; ob < operbasis.size(); ob++) {
804  double dist = operbasis[ob].min_dist(basis[b], tshift);
805  if(dist < smallest) {
806  bshift = tshift;
807  smallest = dist;
808  }
809  }
810  bshift.cart() *= (1.0 / relaxed_factors.size());
811  avg_basis[b] += bshift;
812  }
813 
814  }
815 
816  return;
817  }
818 
819  //***********************************************************
827  //***********************************************************
828 
829 
830  template<typename CoordType>
831  void BasicStructure<CoordType>::symmetrize(const double &tolerance) {
832  SymGroup factor_group;
833  generate_factor_group(factor_group, tolerance);
834  symmetrize(factor_group);
835  return;
836  }
837 
838  //***********************************************************
847  //***********************************************************
848 
849  template<typename CoordType>
850  void BasicStructure<CoordType>::add_vacuum_shift(BasicStructure<CoordType> &new_surface_struc, double vacuum_thickness, Eigen::Vector3d shift, COORD_TYPE mode) const {
851 
852  Coordinate cshift(shift, lattice(), mode); //John G 121030
853  if(!almost_zero(cshift.frac(2))) {
854  std::cout << cshift.const_frac() << std::endl;
855  std::cout << "WARNING: You're shifting in the c direction! This will mess with your vacuum and/or structure!!" << std::endl;
856  std::cout << "See BasicStructure<CoordType>::add_vacuum_shift" << std::endl;
857  }
858 
859  Eigen::Vector3d vacuum_vec; //unit vector perpendicular to ab plane
860  vacuum_vec = lattice()[0].cross(lattice()[1]);
861  vacuum_vec.normalize();
862  Lattice new_lattice(lattice()[0],
863  lattice()[1],
864  lattice()[2] + vacuum_thickness * vacuum_vec + cshift.cart()); //Add vacuum and shift to c vector
865 
866  new_surface_struc = *this;
867  new_surface_struc.set_lattice(new_lattice, CART);
868  new_surface_struc.initialize();
869  return;
870  }
871 
872  //***********************************************************
873  template<typename CoordType>
874  void BasicStructure<CoordType>::add_vacuum_shift(BasicStructure<CoordType> &new_surface_struc, double vacuum_thickness, Coordinate shift) const {
875  if(&(shift.home()) != &lattice()) {
876  std::cout << "WARNING: The lattice from your shift coordinate does not match the lattice of your structure!" << std::endl;
877  std::cout << "See BasicStructure<CoordType>::add_vacuum_shift" << std::endl << std::endl;
878  }
879 
880  add_vacuum_shift(new_surface_struc, vacuum_thickness, shift.cart(), CART);
881  return;
882  }
883 
884  //***********************************************************
885  template<typename CoordType>
886  void BasicStructure<CoordType>::add_vacuum(BasicStructure<CoordType> &new_surface_struc, double vacuum_thickness) const {
887  Eigen::Vector3d shift(0, 0, 0);
888 
889  add_vacuum_shift(new_surface_struc, vacuum_thickness, shift, FRAC);
890 
891  return;
892  }
893 
894  //************************************************************
896  template<typename CoordType>
898  Index result(0);
899  for(Index i = 0; i < basis.size(); i++) {
900  if(basis[i].contains("Va"))
901  ++result;
902  }
903  return result;
904  }
905 
906  //************************************************************
907  //read a POSCAR like file and collect all the structure variables
908  //modified to read PRIM file and determine which basis to use
909  //Changed by Ivy to read new VASP POSCAR format
910 
911  template<typename CoordType>
912  void BasicStructure<CoordType>::read(std::istream &stream) {
913  int i, t_int;
914  char ch;
915  Array<double> num_elem;
916  Array<std::string> elem_array;
917  bool read_elem = false;
918  std::string tstr;
919  std::stringstream tstrstream;
920 
921  CoordType tsite(lattice());
922 
923  SD_flag = false;
924  getline(stream, title);
925  if(title.back() == '\r')
926  throw std::runtime_error(std::string("Structure file is formatted for DOS. Please convert to Unix format. (This can be done with the dos2unix command.)"));
927 
928  m_lattice.read(stream);
929 
930  stream.ignore(100, '\n');
931 
932  //Search for Element Names
933  ch = stream.peek();
934  while(ch != '\n' && !stream.eof()) {
935  if(isalpha(ch)) {
936  read_elem = true;
937  stream >> tstr;
938  elem_array.push_back(tstr);
939  ch = stream.peek();
940  }
941  else if(ch == ' ' || ch == '\t') {
942  stream.ignore();
943  ch = stream.peek();
944  }
945  else if(ch >= '0' && ch <= '9') {
946  break;
947  }
948  else {
949  throw std::runtime_error(std::string("Error attempting to read Structure. Error reading atom names."));
950  }
951  }
952 
953  if(read_elem == true) {
954  stream.ignore(10, '\n');
955  ch = stream.peek();
956  }
957 
958  //Figure out how many species
959  int num_sites = 0;
960  while(ch != '\n' && !stream.eof()) {
961  if(ch >= '0' && ch <= '9') {
962  stream >> t_int;
963  num_elem.push_back(t_int);
964  num_sites += t_int;
965  ch = stream.peek();
966  }
967  else if(ch == ' ' || ch == '\t') {
968  stream.ignore();
969  ch = stream.peek();
970  }
971  else {
972  throw std::runtime_error(std::string("Error in line 6 of structure input file. Line 6 of structure input file should contain the number of sites."));
973  }
974  }
975  stream.get(ch);
976 
977  // fractional coordinates or cartesian
978  COORD_MODE input_mode(FRAC);
979 
980  stream.get(ch);
981  while(ch == ' ' || ch == '\t') {
982  stream.get(ch);
983  }
984 
985  if(ch == 'S' || ch == 's') {
986  SD_flag = true;
987  stream.ignore(1000, '\n');
988  while(ch == ' ' || ch == '\t') {
989  stream.get(ch);
990  }
991  stream.get(ch);
992  }
993 
994  if(ch == 'D' || ch == 'd') {
995  input_mode.set(FRAC);
996  }
997  else if(ch == 'C' || ch == 'c') {
998  input_mode.set(CART);
999  }
1000  else if(!SD_flag) {
1001  throw std::runtime_error(std::string("Error in line 7 of structure input file. Line 7 of structure input file should specify Direct, Cartesian, or Selective Dynamics."));
1002  }
1003  else if(SD_flag) {
1004  throw std::runtime_error(std::string("Error in line 8 of structure input file. Line 8 of structure input file should specify Direct or Cartesian when Selective Dynamics is on."));
1005  }
1006 
1007  stream.ignore(1000, '\n');
1008  //Clear basis if it is not empty
1009  if(basis.size() != 0) {
1010  std::cerr << "The structure is going to be overwritten." << std::endl;
1011  basis.clear();
1012  }
1013 
1014  if(read_elem) {
1015  int j = -1;
1016  int sum_elem = 0;
1017  basis.reserve(num_sites);
1018  for(i = 0; i < num_sites; i++) {
1019  if(i == sum_elem) {
1020  j++;
1021  sum_elem += num_elem[j];
1022  }
1023 
1024  tsite.read(stream, elem_array[j], SD_flag);
1025  basis.push_back(tsite);
1026  }
1027  }
1028  else {
1029  //read the site info
1030  basis.reserve(num_sites);
1031  for(i = 0; i < num_sites; i++) {
1032  tsite.read(stream, SD_flag);
1033  if((stream.rdstate() & std::ifstream::failbit) != 0) {
1034  std::cerr << "Error reading site " << i + 1 << " from structure input file." << std::endl;
1035  exit(1);
1036  }
1037  basis.push_back(tsite);
1038  }
1039  }
1040 
1041  // Check whether there are additional sites listed in the input file
1042  std::string s;
1043  getline(stream, s);
1044  std::istringstream tmp_stream(s);
1045  Eigen::Vector3d coord;
1046  tmp_stream >> coord;
1047  if(tmp_stream.good()) {
1048  throw std::runtime_error(std::string("ERROR: too many sites listed in structure input file."));
1049  }
1050 
1051  update();
1052  return;
1053 
1054  }
1055 
1056  //***********************************************************
1057 
1058  template<typename CoordType>
1059  void BasicStructure<CoordType>::print_xyz(std::ostream &stream) const {
1060  stream << basis.size() << '\n';
1061  stream << title << '\n';
1062  stream.precision(7);
1063  stream.width(11);
1064  stream.flags(std::ios::showpoint | std::ios::fixed | std::ios::right);
1065 
1066  for(Index i = 0; i < basis.size(); i++) {
1067  stream << std::setw(2) << basis[i].occ_name() << " ";
1068  stream << std::setw(12) << basis[i].cart() << '\n';
1069  }
1070 
1071  }
1072 
1073  //***********************************************************
1074 
1075  template<typename CoordType>
1076  void BasicStructure<CoordType>::print_cif(std::ostream &stream) const {
1077  const char quote = '\'';
1078  const char indent[] = " ";
1079 
1080  //double amag, bmag, cmag;
1081  //double alpha, beta, gamma;
1082 
1083  // Copying format based on VESTA .cif output.
1084 
1085  // Heading text.
1086 
1087  stream << '#';
1088  for(int i = 0; i < 70; i++) {
1089  stream << '=';
1090  }
1091  stream << "\n\n";
1092  stream << "# CRYSTAL DATA\n\n";
1093  stream << '#';
1094  for(int i = 0; i < 70; i++) {
1095  stream << '-';
1096  }
1097  stream << "\n\n";
1098  stream << "data_CASM\n\n\n";
1099 
1100  stream.precision(5);
1101  stream.width(11);
1102  stream.flags(std::ios::showpoint | std::ios::fixed | std::ios::left);
1103 
1104  stream << std::setw(40) << "_pd_phase_name" << quote << title << quote << '\n';
1105  stream << std::setw(40) << "_cell_length_a" << lattice().lengths[0] << '\n';
1106  stream << std::setw(40) << "_cell_length_b" << lattice().lengths[1] << '\n';
1107  stream << std::setw(40) << "_cell_length_c" << lattice().lengths[2] << '\n';
1108  stream << std::setw(40) << "_cell_angle_alpha" << lattice().angles[0] << '\n';
1109  stream << std::setw(40) << "_cell_angle_beta" << lattice().angles[1] << '\n';
1110  stream << std::setw(40) << "_cell_angle_gamma" << lattice().angles[2] << '\n';
1111  stream << std::setw(40) << "_symmetry_space_group_name_H-M" << quote << "TBD" << quote << '\n';
1112  stream << std::setw(40) << "_symmetry_Int_Tables_number" << "TBD" << "\n\n";
1113 
1114  stream << "loop_\n";
1115  stream << "_symmetry_equiv_pos_as_xyz\n";
1116 
1117  // Equivalent atom positions here. Form: 'x, y, z', '-x, -y, -z', 'x+1/2, y+1/2, z', etc.
1118  // Use stream << indent << etc.
1119 
1120  stream << '\n';
1121  stream << "loop_\n";
1122  stream << indent << "_atom_site_label" << '\n';
1123  stream << indent << "_atom_site_occupancy" << '\n';
1124  stream << indent << "_atom_site_fract_x" << '\n';
1125  stream << indent << "_atom_site_fract_y" << '\n';
1126  stream << indent << "_atom_site_fract_z" << '\n';
1127  stream << indent << "_atom_site_adp_type" << '\n';
1128  stream << indent << "_atom_site_B_iso_or_equiv" << '\n';
1129  stream << indent << "_atom_site_type_symbol" << '\n';
1130 
1131  // Use stream << indent << etc.
1132  }
1133 
1134  //***********************************************************
1135 
1136  template<typename CoordType>
1138 
1139  for(Index i = 0; i < basis.size(); i++) {
1140  basis[i] += shift;
1141  }
1142 
1143  //factor_group += shift;
1144  //asym_unit += shift;
1145  return (*this);
1146  }
1147 
1148 
1149  //***********************************************************
1150 
1151  template<typename CoordType>
1153 
1154  for(Index i = 0; i < basis.size(); i++) {
1155  basis[i] -= shift;
1156  }
1157  //factor_group -= shift;
1158  //asym_unit -= shift;
1159  return (*this);
1160  }
1161 
1162  //***********************************************************
1163 
1164  template<typename CoordType>
1166 
1167  return BasicStructure<CoordType>(RHS).apply_sym(LHS);
1168  }
1169 
1170  //***********************************************************
1171 
1172  template<typename CoordType>
1174  BasicStructure<CoordType> tsuper(LHS);
1175  tsuper.fill_supercell(RHS);
1176  return tsuper;
1177  }
1178 
1179  //****************************************************
1180 
1181  template<typename CoordType>
1183  json.put_obj();
1184 
1185  // std::string title;
1186  json["title"] = title;
1187 
1188  // Lattice lattice;
1189  json["lattice"] = lattice();
1190 
1191  // Array<CoordType> basis;
1192  json["basis"] = basis;
1193 
1194  return json;
1195  }
1196 
1197  //****************************************************
1198 
1199  // Assumes constructor CoordType::CoordType(Lattice) exists
1200  template<typename CoordType>
1202  try {
1203 
1204  // std::string title;
1205  CASM::from_json(title, json["title"]);
1206 
1207  // Lattice lattice;
1208  CASM::from_json(m_lattice, json["lattice"]);
1209 
1210  // Array<CoordType> basis;
1211  basis.clear();
1212  CoordType coordtype(lattice());
1213  for(int i = 0; i < json["basis"].size(); i++) {
1214  CASM::from_json(coordtype, json["basis"][i]);
1215  basis.push_back(coordtype);
1216  }
1217 
1218  }
1219  catch(...) {
1221  throw;
1222  }
1223 
1224  }
1225 
1226  //****************************************************
1227 
1228  template<typename CoordType>
1230  return basic.to_json(json);
1231  }
1232 
1233  // Assumes constructor CoordType::CoordType(Lattice) exists
1234  template<typename CoordType>
1235  void from_json(BasicStructure<CoordType> &basic, const jsonParser &json) {
1236  basic.from_json(json);
1237  }
1238 
1239 
1240 }
1241 
void from_json(const jsonParser &json)
void print_cif(std::ostream &stream) const
size_type size() const
Returns array size if *this is a JSON array, object size if *this is a JSON object, 1 otherwise.
Definition: jsonParser.cc:430
virtual void sort()
Sort SymOp in the SymGroup.
Definition: SymGroup.cc:3574
void set_site_internals()
Associate each site with its basis index by setting its internal flags (asym_ind -> -1) ...
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:41
void map_superstruc_to_prim(BasicStructure &prim, const SymGroup &point_group)
Figures out which prim basis each superstructure basis corresponds to.
jsonParser & to_json(jsonParser &json) const
void fill_supercell(const BasicStructure &prim, double map_tol=TOL)
fill an empty structure with the basis of its corresponding primitive cell
static SymOp translation(const Eigen::Ref< const vector_type > &_tau)
static method to create operation that describes pure translation
Definition: SymOp.hh:35
bool contains(const T &test_elem) const
Definition: Array.hh:281
void from_json(ClexDescription &desc, const jsonParser &json)
Index size() const
Definition: Array.hh:145
Coordinate_impl::CartCoordinate cart()
Set Cartesian coordinate vector and update fractional coordinate vector.
Definition: Coordinate.hh:593
Type-safe ID object for communicating and accessing Symmetry representation info. ...
void generate_point_group(SymGroup &point_group, double pg_tol=TOL) const
Populate.
Definition: Lattice.cc:304
bool compare(const T &A, const T &B, double tol)
Floating point comparison with tol, return A < B.
Definition: CASM_math.hh:89
void push_back(const T &toPush)
Definition: Array.hh:513
virtual void clear()
Definition: SymGroup.cc:490
jsonParser & to_json(const ClexDescription &desc, jsonParser &json)
void add_vacuum(BasicStructure &new_surface_struc, double vacuum_thickness) const
Adds vacuum layer on top of ab plane.
bool is_primitive(double prim_tol=TOL) const
BasicStructure specifies the lattice and atomic basis of a crystal.
Definition: Cluster.hh:16
Unit Cell Coordinates.
SymBasisPermute describes how a symmetry operation permutes atoms in a basis.
BasicStructure create_superstruc(const Lattice &scel_lat, double map_tol=TOL) const
Shortcut routine to create a supercell structure and fill it with sites.
BasicStructure & operator+=(const Coordinate &shift)
Translates all atoms in cell.
void generate_factor_group_slow(SymGroup &factor_group, double map_tol) const
Main CASM namespace.
Definition: complete.cpp:8
const Lattice & lattice() const
const double TOL
void symmetrize(const SymGroup &relaxed_factors)
Derived::Scalar triple_prod(const Derived &vec0, const Derived &vec1, const Derived &vec2)
void set_lattice(const Lattice &lattice, COORD_TYPE mode)
void generate_factor_group(SymGroup &factor_group, double map_tol) const
apply a symmetry operation to the current structure (may change lattice vectors and order of basis at...
const Array< Index >::X2 & get_multi_table() const
Definition: SymGroup.cc:3170
const vector_type & const_frac() const
user override to force const Access the fractional coordinate vector
Definition: Coordinate.hh:66
static Coordinate origin(const Lattice &_home)
construct a coordinate describing origin of _home lattice
Definition: Coordinate.hh:296
Index find(const CoordType2 &test_site, double tol=TOL) const
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
Definition: SymGroup.hh:33
void set_map_error(const double &value)
Definition: SymOp.cc:15
double tol
void clear()
Definition: Array.hh:216
double min_dist(const Coordinate &neighbor) const
Returns distance (in Angstr) to nearest periodic image of neighbor.
Definition: Coordinate.cc:155
void print_xyz(std::ostream &stream) const
Output other formats.
COORD_MODE specifies the current coordinate mode (Fractional or Cartesian)
SymOp is the Coordinate representation of a symmetry operation it keeps fraction (FRAC) and Cartesian...
Definition: SymOp.hh:28
BasisSet operator*(const SymOp &LHS, const BasisSet &RHS)
Definition: BasisSet.cc:1154
Represents cartesian and fractional coordinates.
Definition: Coordinate.hh:34
double max_error()
This returns the group's max_error.
Definition: SymGroup.cc:933
EigenIndex Index
For long integer indexing:
void add_vacuum_shift(BasicStructure &new_surface_struc, double vacuum_thickness, Eigen::Vector3d shift, COORD_TYPE mode) const
Add vacuum and shift c vector. The vacuum is always added parallel to c, and the shift vector should ...
const Array< std::complex< double > >::X2 & character_table() const
Definition: SymGroup.cc:3212
void set_basis(Array< CoordType > basis_in)
Manually set the basis sites.
Array< CoordType > basis
Lattice vectors that specifies periodicity of the crystal.
Index max_possible_vacancies() const
Counts sites that allow vacancies.
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.
void fg_converge(double small_tol, double large_tol, double increment)
Iterator find(Iterator begin, Iterator end, const T &value, BinaryCompare q)
Equivalent to std::find(begin, end, value), but with custom comparison.
Definition: algorithm.hh:10
void set(const COORD_TYPE new_mode)
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
std::string title
User-specified name of this Structure.
BasicStructure & operator-=(const Coordinate &shift)
virtual void read(std::istream &stream)
Print intpolated images in seperate directries.
Index find_no_trans(const SymOp &test_op) const
Check to see if a SymOp is contained in in SymGroup and return its index.
Definition: SymGroup.cc:3309
bool is_group(double tol=TOL) const
Check to see if SymGroup satisfies the group property.
Definition: SymGroup.cc:3346
void copy_attributes_from(const BasicStructure &RHS)
Eigen::Matrix3d Matrix3d
jsonParser & put_obj()
Puts new empty JSON object.
Definition: jsonParser.hh:276
CoordType get_site(const UnitCellCoord &ucc) const
UnitCellCoord get_unit_cell_coord(const CoordType2 &test_site, double tol=TOL) const
virtual void push_back(const SymOp &new_op)
Definition: SymGroup.cc:441
Coordinate_impl::FracCoordinate frac()
Set the fractional coordinate vector.
Definition: Coordinate.hh:581
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
SymGroupRep is an alternative representation of a SymGroup for something other than real space...
Definition: SymGroupRep.hh:30
SymGroupRepID generate_basis_permutation_representation(const MasterSymGroup &factor_group, bool verbose) const
void within()
Translate all basis sites so that they are inside the unit cell.
const std::string & get_name() const
Definition: SymGroup.cc:3220
T & back()
Definition: Array.hh:177
const Lattice & home() const
Access the home lattice of the coordinate.
Definition: Coordinate.hh:195
bool contains(const Container &container, const T &value)
Equivalent to container.end() != std::find(container.begin(), container.end(), value) ...
Definition: algorithm.hh:66
Lattice niggli(const Lattice &in_lat, double compare_tol, bool keep_handedness=false)
Convert the given lattice into it's niggli reduced form, with the most standard orientation possilbe...
Definition: Niggli.cc:240
SymGroupRepID add_representation(const SymGroupRep &new_rep) const
Add a new representation by passing a reference. SymGroup will store a copy.
Definition: SymGroup.cc:361
bool is_primitive(const Configuration &_config)
returns true if _config describes primitive cell of the configuration it describes ...
virtual BasicStructure & operator=(const BasicStructure &RHS)
void set_rep(const SymOpRepresentation &base_rep, const SymOpRepresentation &new_rep) const
Definition: SymGroupRep.cc:82