CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
Orbitree_impl.hh
Go to the documentation of this file.
2 #include "casm/misc/algorithm.hh"
3 
4 namespace CASM {
5 
6  //John G 011013
7  //********************************************************************
8  //Copy constructor
9  template<typename ClustType>
11  Array<GenericOrbitBranch<ClustType> >(), m_asym_unit(lattice) {
12  //set_lattice(starttree.lattice, FRAC);
13 
14  //copy members
15  lattice = starttree.lattice;
16  max_num_sites = starttree.max_num_sites;
18  max_length = starttree.max_length;
19  min_length = starttree.min_length;
20  num_clusts = starttree.num_clusts;
21  index_to_row = starttree.index_to_row;
22  index_to_column = starttree.index_to_column;
23  index = starttree.index;
24  Norbits = starttree.Norbits;
25  subcluster = starttree.subcluster;
26  m_bspecs = starttree.bspecs();
27  m_b2asym = starttree.m_b2asym;
28  m_tol = starttree.m_tol;
29 
30  //copy all orbitbranches over
31  m_asym_unit = starttree._asym_unit();
32  m_asym_unit.set_lattice(lattice, CART);
33  for(Index b = 0; b < starttree.size(); b++) {
34  push_back(starttree[b]);
35  }
36  };
37  //********************************************************************
38 
39  template<typename ClustType>
41  return m_tol;
42  }
43 
44  //********************************************************************
45 
46  template<typename ClustType>
48  return at(np).at(no);
49  }
50 
51  //********************************************************************
52 
53  template<typename ClustType>
55  return at(np).at(no);
56  }
57 
58  //********************************************************************
59 
60  template<typename ClustType>
61  const ClustType &GenericOrbitree<ClustType>::prototype(Index np, Index no) const {
62  return at(np).at(no).prototype;
63  }
64 
65  //********************************************************************
66 
67  template<typename ClustType>
69  return at(np).at(no).prototype;
70  }
71 
72  //********************************************************************
73 
74  template<typename ClustType>
75  const ClustType &GenericOrbitree<ClustType>::equiv(Index np, Index no, Index ne) const {
76  return at(np).at(no).at(ne);
77  }
78 
79  //********************************************************************
80 
81  template<typename ClustType>
83  return at(np).at(no).at(ne);
84  }
85 
86  //********************************************************************
87 
88  template<typename ClustType>
90  return at(np).size();
91  }
92 
93  //********************************************************************
94 
95  template<typename ClustType>
97  return orbit(np, no).size();
98  }
99 
100  //********************************************************************
101 
102  // Count number of basis functions at each orbit and sum result
103  template<typename ClustType>
105  Index result(0);
106  for(Index np = 0; np < size(); np++) {
107  for(Index no = 0; no < at(np).size(); no++) {
108  result += prototype(np, no).clust_basis.size();
109  }
110  }
111  return result;
112  }
113 
114  //*******************************************************************************************
115 
116  template<typename ClustType>
119  }
120 
121  //********************************************************************
122 
123  template<typename ClustType>
125  Array<GenericOrbitBranch<ClustType> >::push_back(new_branch);
126  back().set_lattice(lattice, CART);
127  return;
128  }
129 
130 
131  //********************************************************************
132 
133  template<typename ClustType>
135  //Add the orbit where it needs to go.
136  for(Index np = 0; np < size(); np++) {
137  if(at(np).num_sites() == new_orbit.prototype.size()) {
138  at(np).push_back(new_orbit);
139  return;
140  }
141  }
142 
143  push_back(GenericOrbitBranch<ClustType>(lattice));
144  back().push_back(new_orbit);
145  }
146 
147  //********************************************************************
148 
149  template<typename ClustType>
151  for(Index nb = 0; nb < size(); nb++)
152  at(nb).set_lattice(new_lat, mode);
153 
154  lattice = new_lat;
155 
156  for(Index nb = 0; nb < size(); nb++)
157  at(nb).set_lattice(lattice, mode);
158 
159  //phenom_clust.set_lattice(lattice, mode);
160 
161  }
162  //********************************************************************
163 
164  template<typename ClustType>
166  //Loops over outer array which is the outer array of the point, pair, etc clusters (np stands for cluster size)
167  for(Index np = 0; np < size(); np++) {
168  sort(np);
169  }
170  return;
171  }
172 
173  //********************************************************************
174 
175  template<typename ClustType>
177  at(np).sort();
178  }
179 
180  //********************************************************************
181 
182  template<typename ClustType>
184  generate_clust_bases(std::vector<BasisSet const *>(), max_poly_order);
185  }
186 
187  //********************************************************************
188 
189  template<typename ClustType>
190  void GenericOrbitree<ClustType>::generate_clust_bases(std::vector<BasisSet const *> const &global_args, Index max_poly_order) {
191  _populate_site_bases();
192 
193  Array<BasisSet> sitebases(m_b2asym.size());
194  for(Index b = 0; b < m_b2asym.size(); b++)
195  sitebases[b] = _asym_unit().equiv(m_b2asym[b][0], m_b2asym[b][1]).clust_basis;
196 
197  for(Index i = 0; i < size(); i++) {
198  for(Index j = 0; j < size(i); j++) {
199  multivector<const BasisSet *>::X<2> local_args(1);
200  for(Index ns = 0; ns < prototype(i, j).size(); ns++) {
201  local_args.back().push_back(&sitebases[prototype(i, j)[ns].basis_ind()]);
202  }
203 
204  // Should this step be a method of Orbit?
205  prototype(i, j).generate_clust_basis(local_args, global_args);
206  for(Index k = 0; k < size(i, j); k++) {
207  equiv(i, j, k).clust_basis = prototype(i, j).clust_basis;
208  equiv(i, j, k).clust_basis.apply_sym(orbit(i, j).equivalence_map[k][0]);
209 
210  // next: critical step -- make sure that dof IDs are up to date in equivalent basis functions
211  //std::cout << "Updating clust_basis of equiv:\n";
212 
213  // we may also need to permute the indices when updating dof IDs (but probably not)
214  equiv(i, j, k).clust_basis.set_dof_IDs(equiv(i, j, k).nlist_inds());
215  }
216  }
217  }
218  }
219 
220  //********************************************************************
221 
222  template<typename ClustType>
224  _generate_asym_unit(struc);
225 
226  for(Index np = 0; np < size(); np++)
227  for(Index no = 0; no < size(np); no++)
228  orbit(np, no).collect_basis_info(struc.basis);
229  }
230 
231  //********************************************************************
232  template<typename ClustType>
233  Index GenericOrbitree<ClustType>::find(const ClustType &test_clust) const {
234  Index i, j, ind;
235 
236  ind = 0;
237  //Find the OrbitBranch of our current Orbitree - loop through number of OrbitBranches
238  for(i = 0; i < size(); i++) {
239 
240  //If we're in an OrbitBranch with size of clusters equal to those in test_clust, try to find test_clust
241  if(at(i).num_sites() == test_clust.size()) {
242 
243  //Loop through all j Orbits in i Orbitbranch:
244  for(j = 0; j < at(i).size(); j++) {
245  if(orbit(i, j).contains(test_clust, tol()))
246  return ind + j; //Return the linear orbit index test_clust is found in
247  }
248  }
249  ind += size(i);
250  }
251  return ind;
252  }
253 
254  //*******************************
255 
256  // Find a cluster within a specified Orbitbranch. Return the index of the Orbit
257  // in which test_clust lives, relative to that specific OrbitBranch (i.e. the
258  // first Orbit in this branch, regardless of its position in Orbitree, has an index of 0).
259  template<typename ClustType>
260  Index GenericOrbitree<ClustType>::find(const ClustType &test_clust, Index nb) const {
261  Index i;
262 
263  //Loop through all i Orbits in Orbitbranch with index nb:
264  for(i = 0; i < at(nb).size(); i++) {
265  if(orbit(nb, i).contains(test_clust, tol()))
266  return i; //Return the Orbit test_clust is found in
267  }
268 
269  return i; //Return the total number of Orbits in Orbitbrach nb if test_clust isn't found
270  }
271 
272  //********************************************************************
273 
274  template<typename ClustType>
276  Index i, j, ind;
277 
278  ind = 0;
279 
280  //Find the OrbitBranch of our current Orbitree - loop through number of OrbitBranches
281  for(i = 0; i < size(); i++) {
282 
283  //If we're in an OrbitBranch with np equal to the size of clusters in the prototype cluster of test_orbit, try to find test_orbit
284  if(at(i).num_sites() == test_orbit.prototype.size()) {
285 
286  //Loop through all j Orbits in i Orbitbranch:
287  for(j = 0; j < at(i).size(); j++) {
288  if(at(i).orbit(j) == test_orbit) //at(i) finds OrbitBranch, and then use OrbitBranch's orbit(no) fxn
289  return ind + j;
290  }
291  ind += size(i);
292  }
293  }
294  return ind; //Return the total number of Orbits if test_clust isn't found
295  }
296 
297  //*******************************
298 
299  template<typename ClustType>
300  bool GenericOrbitree<ClustType>::contains(const ClustType &test_clust) {
301  for(Index i = 0; i < size(); i++) {
302  if(find(test_clust, i) < at(i).size())
303  return true;
304  }
305  return false;
306 
307  }
308 
309  //*******************************
310 
311  template<typename ClustType>
312  void GenericOrbitree<ClustType>::get_index() const { //(Line 4826 in clusters11.0.h)
313  Index count = 0;
314  index.clear();
315  index_to_row.clear();
316  index_to_column.clear();
317  index.resize(size());
318 
319  // Loop over the clusters with the same number of points (np),
320  // then inside that loop, loop over all those clusters (nc)
321 
322 
323  // Note: Should we make sure to sort the GenericOrbitree<ClustType> first so we
324  // don't have to switch any index values around?
325 
326 
327  for(Index np = 0; np < size(); np++) { //Start with point clusters (np=1)
328  for(Index no = 0; no < size(np); no++) { //no = index of inner array (over orbits)
329  orbit(np, no).set_index(count);
330  index[np].push_back(count);
331  index_to_row.push_back(np);
332  index_to_column.push_back(no);
333  count++;
334 
335  }
336  }
337 
338  Norbits = count; // Brian (index.back().back() doesn't work if the last orbitBranch has no orbits
339  return;
340  }
341 
342  //************************************************************
343  //
344  // Constructs an orbitree given a primitive Structure.
345  //
346  // First finds the asymmetric unit, from which it constructs
347  // all the pair clusters within a radii specified in max_length.
348  // From the pair clusters, it constructs triplet clusters,
349  // then from the triplet clusters it builds the quadruplet
350  // clusters and so on so forth.
351  //
352  //************************************************************
353 
354  template<typename ClustType>
356 
357  if(prim.factor_group().size() == 0) {
358  std::cerr << "WARNING: In Orbitree::generate_orbitree, prim's factor_group is empty. It must at least have one element (identity).\n";
359  assert(0);
360  }
361 
362  Index i, j, np, no;
363  Eigen::Vector3i dim; //size of gridstruc
364  double dist, min_dist;
366  std::string clean(80, ' ');
367 
368  lattice = prim.lattice();
369  Coordinate lat_point(lattice);
370 
371 
372  //first get the basis sites
373 
374  if(verbose) std::cout << "* Finding Basis:\n";
375  // make the basis from which the sites for the local clusters are to be picked
376  for(i = 0; i < prim.basis.size(); i++) {
377  if(prim.basis[i].site_occupant().size() >= min_num_components) {
378  basis.push_back(prim.basis[i]);
379  basis.back().set_lattice(lattice, CART);
380  }
381  }
382 
383  double max_radius = max_length.max();
384  dim = lattice.enclose_sphere(max_radius);
385  EigenCounter<Eigen::Vector3i > grid_count(-dim, dim, Eigen::Vector3i::Constant(1));
386  if(verbose) std::cout << "dim is " << dim << '\n';
387  if(verbose) std::cout << "\n Finding Grid_struc:\n";
388  do {
389  lat_point.frac() = grid_count().cast<double>();
390 
391  for(i = 0; i < basis.size(); i++) {
392  typename ClustType::WhichCoordType tatom(basis[i] + lat_point);
393  //get distance to closest basis site in the unit cell at the origin
394 
395  min_dist = 1e20;
396  for(j = 0; j < basis.size(); j++) {
397  dist = tatom.dist(basis[j]);
398  if(dist < min_dist)
399  min_dist = dist;
400  }
401  if(min_dist < max_radius) {
402  gridstruc.push_back(tatom);
403  }
404  }
405  }
406  while(++grid_count);
407 
408  if(verbose) std::cout << "Finished finding grid_struc\n";
409  // Get orbitree ready to hold clusters.
410  if(size())
411  std::cerr << "WARNING: Orbitree is about to be overwritten! Execution will continue normally, but side effects may occur.\n";
412 
413  //Size outer arry to have sufficient space to create orbitree
414  resize(max_num_sites + 1);
415 
416 
417  // Add orbit corresponding to empty cluster
418  at(0).push_back(GenericOrbit<ClustType>(ClustType(lattice)));
419  at(0).back().get_equivalent(prim.factor_group(), tol());
420 
421 
422  //for each cluster of the previous size, add points from gridstruc
423  // - see if the new cluster satisfies the size requirements
424  // - see if it is new
425  // - generate all its equivalents
426 
427  if(verbose) std::cout << "About to begin construction of non-empty clusters\n";
428  else std::cout << clean << '\r' << "About to begin construction of non-empty clusters\r" << std::flush;
429  for(np = 1; np <= max_num_sites; np++) {
430  if(verbose) std::cout << "Doing np = " << np << '\n';
431  else std::cout << clean << '\r' << "Doing np = " << np << '\r' << std::flush;
432 
433  if(size(np - 1) == 0) {
434  std::cerr << "CRITICAL ERROR: Orbitree::generate_orbitree is unable to enumerate clusters of size " << np << '\n';
435  get_index();
436  print(std::cout);
437  exit(1);
438  }
439 
440  for(no = 0; no < size(np - 1); no++) {
441  if(verbose) std::cout << "Adding sites to orbit " << no << " of " << size(np - 1) << "\n";
442  else std::cout << clean << '\r' << "Adding sites to orbit " << no << " of " << size(np - 1) << " in branch " << np - 1 << '\r' << std::flush;
443 
444  ClustType tclust(lattice);
445  for(i = 0; i < orbit(np - 1, no).prototype.size(); i++)
446  tclust.push_back(orbit(np - 1, no).prototype[i]);
447 
448  for(i = 0; i < gridstruc.size(); i++) {
449 
450  if(tclust.contains(gridstruc[i]))
451  continue;
452 
453  //tclust = orbit(np - 1, no).prototype;
454  tclust.push_back(gridstruc[i]);
455 
456  tclust.within();
457  tclust.calc_properties();
458 
459  if(np == 1 && !contains(tclust)) {
460  at(np).push_back(GenericOrbit<ClustType>(tclust));
461  at(np).back().get_equivalent(prim.factor_group(), tol());
462  }
463  else if(tclust.max_length() < max_length[np] && tclust.min_length() > min_length && !contains(tclust)) {
464  at(np).push_back(GenericOrbit<ClustType>(tclust));
465 
466  at(np).back().get_equivalent(prim.factor_group(), tol());
467  }
468  tclust.pop_back();
469  }
470  }
471  }
472 
473  if(!verbose) std::cout << clean << '\r' << std::flush;
474 
475  sort();
476  get_index();
477  return;
478  }
479 
480  //****************************************************************************************************************
481  //
482  // Constructs an orbitree given a primitive Structure and the max number of clusters that the user wants
483  //
484  // First generates a ballpark estimate of the minimum supercell size. Assuming the absence of symmetry,
485  // given an nxnxn supercell, the number of clusters that may be generated is given by (the number of ways we can
486  // choose pair clusters from the primitive structure)+
487  // (the number of ways pair clusters may be chosen from 2 cells)(the number of ways we can choose 2 primitive
488  // cells in the superlattice). This formula is inverted to give the number of supercells needed to generate a
489  // given number of clusters.
490  // The grid is built with that ballpark estimate, pair clusters are generated within that grid. If enough pair
491  // clusters havent been generated, a bigger grid is made. This is continued till the maxClust criterion is
492  // satisfied.
493  //
494  //*****************************************************************************************************************
495 
496  template<typename ClustType>
497  void GenericOrbitree<ClustType>::generate_orbitree(const Structure &prim, const int maxClust) {
498  Index i, j, np, no;
499  int numClust, ctr;
500  Eigen::Vector3i dim; //size of gridstruc
501  double maxClustLength;
504  lattice = prim.lattice();
505  double min_lat_length = min(min(prim.lattice().length(0), prim.lattice().length(1)), prim.lattice().length(2));
506  Coordinate lat_point(lattice);
507 
508  //first get the basis sites
509  std::cout << "** Finding Basis:\n";
510  // make the basis from which the sites for the local clusters are to be picked
511 
512  for(i = 0; i < prim.basis.size(); i++) {
513  if(prim.basis[i].site_occupant().size() >= min_num_components) {
514  basis.push_back(prim.basis[i]);
515  basis.back().set_lattice(lattice, CART);
516  }
517  }
518 
519  //Get a ballpark estimate of the number of cells required
520  int cellSize = ceil(pow(((maxClust - (basis.size() * (basis.size() - 1)) / 2.0) / (basis.size() * (2 * basis.size() - 1.0)) + 1.0), 1.0 / 3.0));
521 
522  //Build initial grid
523  double max_radius = (cellSize) * min_lat_length;
524  ctr = 0;
525  dim = lattice.enclose_sphere(max_radius);
526  gridstruc = lattice.gridstruc_build(max_radius, double(0), basis, lat_point);
527  double min_radius = max_radius;
528  std::cout << dim << " " << cellSize << "\n";
529 
530 
531  // Get orbitree ready to hold clusters.
532 
533  if(size())
534  std::cerr << "WARNING: Orbitree is about to be overwritten! Execution will continue normally, but side effects may occur.\n";
535 
536  //Size outer arry to have sufficient space to create orbitree
537  resize(max_num_sites + 1);
538 
539 
540  // Add orbit corresponding to empty cluster
541  at(0).push_back(GenericOrbit<ClustType>(ClustType(lattice)));
542  at(0).back().get_equivalent(prim.factor_group(), tol());
543 
544 
545  //for each cluster of the previous size, add points from gridstruc
546  // - see if the new cluster satisfies the size requirements
547  // - see if it is new
548  // - generate all its equivalents
549 
550  std::cout << "About to begin construction of non-empty clusters\n";
551 
552  for(np = 1; np <= max_num_sites; np++) {
553  std::cout << "Doing np = " << np << '\n';
554 
555  if(size(np - 1) == 0) {
556  std::cerr << "CRITICAL ERROR: Orbitree::generate_orbitree is unable to enumerate clusters of size " << np << '\n';
557  get_index();
558  print(std::cout);
559  exit(1);
560  }
561  // If the pair clusters are being built, we need to keep track of the number of clusters that have been found so far
562  if(np == 2) {
563  maxClustLength = 0;
564  i = 0;
565  numClust = 0;
566  do {
567  for(no = 0; no < size(np - 1); no++) {
568  std::cout << "Adding sites to orbit " << no << " of " << size(np - 1) << "\n";
569 
570  ClustType tclust(lattice);
571  for(j = 0; j < orbit(np - 1, no).prototype.size(); j++)
572  tclust.push_back(orbit(np - 1, no).prototype[j]);
573 
574  for(; i < gridstruc.size(); i++) {
575 
576  if(tclust.contains(gridstruc[i]))
577  continue;
578 
579  tclust.push_back(gridstruc[i]);
580 
581  tclust.within();
582  tclust.calc_properties();
583 
584  if(tclust.min_length() > min_length && !contains(tclust)) {
585  std::cout << "Found a new cluster.... adding to Orbitree!\n";
586  std::cout << "The minimum length is " << min_length << "\n";
587  at(np).push_back(GenericOrbit<ClustType>(tclust));
588  at(np).back().get_equivalent(prim.factor_group(), tol());
589  numClust = numClust + 1;
590  if(maxClustLength < tclust.max_length()) {
591  maxClustLength = tclust.max_length();
592  }
593  }
594  tclust.pop_back();
595  }
596  }
597  if(numClust < maxClust) {
598  //Building a bigger grid!
599  dim += Eigen::Vector3i::Ones();
600  ctr += 1;
601  std::cout << "Max Radius" << max_radius << "\n";
602  max_radius = (cellSize + ctr) * min_lat_length;
603  std::cout << "Max Radius" << max_radius << "\n";
604  gridstruc.append(lattice.gridstruc_build(max_radius, min_radius, basis, lat_point));
605  min_radius = max_radius;
606  std::cout << "Built a bigger grid!\n" << gridstruc.size() << "\n";
607  //End of building a bigger grid
608  }
609  std::cout << "Couldnt find enough points " << numClust << " " << i << " " << maxClust << "\n";
610  }
611  while(numClust < maxClust);
612  sort(np);
613 
614  //Once more clusters than required are found, only the first 'maxClust' number of clusters are kept, which one to keep and which one to remove is decided based on the length of the cluster
615  double cutOff = orbit(np, maxClust - 1).max_length();
616  std::cout << cutOff << " Cutoff!\n";
617  for(i = maxClust; i < size(np); i++) {
618  if(orbit(np, i).max_length() > cutOff) {
619  std::cout << orbit(np, i).max_length() << " " << orbit(np, i).min_length() << "Deleted this\n";
620  at(np).remove(i);
621  i = i - 1;
622  }
623  }
624 
625  continue;
626  }
627 
628  max_length[np] = maxClustLength;
629  for(no = 0; no < size(np - 1); no++) {
630  std::cout << "Adding sites to orbit " << no << " of " << size(np - 1) << "\n";
631 
632  ClustType tclust(lattice);
633  for(i = 0; i < orbit(np - 1, no).prototype.size(); i++)
634  tclust.push_back(orbit(np - 1, no).prototype[i]);
635 
636  for(i = 0; i < gridstruc.size(); i++) {
637 
638  if(tclust.contains(gridstruc[i]))
639  continue;
640 
641  tclust.push_back(gridstruc[i]);
642 
643 #ifdef DEBUG
644  std::cout << "tclust is \n"
645  << tclust << "\n";
646 #endif //DEBUG
647 
648  tclust.within();
649  tclust.calc_properties();
650 
651 #ifdef DEBUG
652  std::cout << "tclust is \n"
653  << tclust << "\n";
654 #endif //DEBUG
655 
656  if(np == 1 && !contains(tclust)) {
657  at(np).push_back(GenericOrbit<ClustType>(tclust));
658  at(np).back().get_equivalent(prim.factor_group(), tol());
659  }
660  else if(tclust.max_length() < max_length[np] && tclust.min_length() > min_length && !contains(tclust)) {
661  std::cout << "Found a new cluster.... adding to Orbitree!\n";
662  std::cout << "The minimum length is " << min_length << "\n";
663  at(np).push_back(GenericOrbit<ClustType>(tclust));
664 
665 #ifdef DEBUG
666  std::cout << "The tclust we pushed back is \n"
667  << tclust << "\n";
668 #endif //DEBUG
669  at(np).back().get_equivalent(prim.factor_group(), tol());
670  }
671  tclust.pop_back();
672  }
673  }
674  }
675  sort();
676  get_index();
677  return;
678  }
679 
680  //****************************************************************************************************************
681  // Generates all orbitrees upto the nth nearest neighbour as specified in the input array maxNeighbour.
682  //*****************************************************************************************************************
683  template<typename ClustType>
685  Index i, j, np, no;
686  int numClust, ctr;
687  Eigen::Vector3i dim; //size of gridstruc
688  double maxClustLength;
691  Array<double> neighbour_lengths;
692  lattice = prim.lattice();
693  Coordinate lat_point(lattice);
694  double min_lat_length = min(min(prim.lattice().length(0), prim.lattice().length(1)), prim.lattice().length(2));
695 
696  //first get the basis sites
697  std::cout << "*** Finding Basis:\n";
698  // make the basis from which the sites for the local clusters are to be picked
699 
700  for(i = 0; i < prim.basis.size(); i++) {
701  if(prim.basis[i].site_occupant().size() >= min_num_components) {
702  basis.push_back(prim.basis[i]);
703  basis.back().set_lattice(lattice, CART);
704  }
705  }
706  //Get a ballpark estimate of the number of cells required
707  int cellSize = 1;
708 
709  //Build initial grid
710  double max_radius = (cellSize) * min_lat_length;
711  ctr = 0;
712  dim = lattice.enclose_sphere(max_radius);
713  gridstruc = lattice.gridstruc_build(max_radius, double(0), basis, lat_point);
714  double min_radius = max_radius;
715  std::cout << dim << " " << cellSize << "\n";
716 
717  // Get orbitree ready to hold clusters.
718 
719  if(size())
720  std::cerr << "WARNING: Orbitree is about to be overwritten! Execution will continue normally, but side effects may occur.\n";
721 
722  //Size outer arry to have sufficient space to create orbitree
723  resize(max_num_sites + 1);
724 
725  // Add orbit corresponding to empty cluster
726  at(0).push_back(GenericOrbit<ClustType>(ClustType(lattice)));
727  at(0).back().get_equivalent(prim.factor_group(), tol());
728 
729  //for each cluster of the previous size, add points from gridstruc
730  // - see if the new cluster satisfies the size requirements
731  // - see if it is new
732  // - generate all its equivalents
733 
734  std::cout << "About to begin construction of non-empty clusters\n";
735 
736  for(np = 1; np <= max_num_sites; np++) {
737  std::cout << "Doing np = " << np << '\n';
738 
739  if(size(np - 1) == 0) {
740  std::cerr << "CRITICAL ERROR: Orbitree::generate_orbitree is unable to enumerate clusters of size " << np << '\n';
741  get_index();
742  print(std::cout);
743  exit(1);
744  }
745  // If the pair clusters are being built, we need to keep track of the number of clusters that have been found so far
746  if(np == 2) {
747  maxClustLength = 0;
748  i = 0;
749  numClust = 0;
750  do {
751  for(no = 0; no < size(np - 1); no++) {
752  std::cout << "Adding sites to orbit " << no << " of " << size(np - 1) << "\n";
753 
754  ClustType tclust(lattice);
755  for(j = 0; j < orbit(np - 1, no).prototype.size(); j++)
756  tclust.push_back(orbit(np - 1, no).prototype[j]);
757 
758 
759  for(; i < gridstruc.size(); i++) {
760 
761  if(tclust.contains(gridstruc[i]))
762  continue;
763 
764  tclust.push_back(gridstruc[i]);
765 
766  tclust.within();
767  tclust.calc_properties();
768 
769  if(tclust.min_length() > min_length && !contains(tclust)) {
770  at(np).push_back(GenericOrbit<ClustType>(tclust));
771  at(np).back().get_equivalent(prim.factor_group(), tol());
772  if(maxClustLength < tclust.max_length()) {
773  maxClustLength = tclust.max_length();
774  }
775  }
776 
777  tclust.pop_back();
778  }
779  }
780 
781  sort(np);
782  numClust = 1;
783  for(Index j = 1; j < size(np); j++) {
784  if(orbit(np, j).max_length() == orbit(np, (j - 1)).max_length()) {
785  continue;
786  }
787  else {
788  numClust = numClust + 1;
789  }
790  }
791 
792  if(numClust < maxNeighbour[0]) {
793  //Building a bigger grid!
794  dim += Eigen::Vector3i::Ones();
795  ctr = ctr + 1;
796  max_radius = (cellSize + ctr) * min_lat_length;
797  gridstruc.append(lattice.gridstruc_build(max_radius, min_radius, basis, lat_point));
798  min_radius = max_radius;
799  //End of building a bigger grid
800  }
801  }
802  while(numClust < maxNeighbour[0]);
803  sort(np);
804  //Once more clusters than required are found, only the first 'maxNeighbour' number of clusters are kept, which one to keep and which one to remove is decided based on the length of the cluster
805  int cutOff = 1;
806  neighbour_lengths.push_back(orbit(np, 0).max_length());
807  for(i = 1; i < size(np); i++) {
808  if(orbit(np, i).max_length() == orbit(np, (i - 1)).max_length()) {
809  continue;
810  }
811  else {
812  neighbour_lengths.push_back(orbit(np, i).max_length());
813  cutOff = cutOff + 1;
814  if(cutOff <= maxNeighbour[0]) {
815  continue;
816  }
817  else {
818  at(np).remove(i);
819  i = i - 1;
820  }
821  }
822  }
823  continue;
824  }
825 
826  std::cout << neighbour_lengths.size() << "\n";
827  if(np != 1) {
828  max_length[np] = neighbour_lengths[(maxNeighbour[np - 2] - 1)];
829  std::cout << "Looking at np=" << np << "\n";
830  }
831  for(no = 0; no < size(np - 1); no++) {
832  if(np != 1 && (orbit(np - 1, no).max_length() > max_length[np] && !almost_zero((orbit(np - 1, no).max_length() - max_length[np])))) {
833  continue;
834  }
835  std::cout << "Adding sites to orbit " << no << " of " << size(np - 1) << "\n";
836 
837  ClustType tclust(lattice);
838  for(i = 0; i < orbit(np - 1, no).prototype.size(); i++)
839  tclust.push_back(orbit(np - 1, no).prototype[i]);
840 
841 
842  for(i = 0; i < gridstruc.size(); i++) {
843 
844  if(tclust.contains(gridstruc[i]))
845  continue;
846 
847  tclust.push_back(gridstruc[i]);
848 
849  tclust.within();
850  tclust.calc_properties();
851 
852  if(np == 1 && !contains(tclust)) {
853  at(np).push_back(GenericOrbit<ClustType>(tclust));
854  at(np).back().get_equivalent(prim.factor_group(), tol());
855  }
856  else if((tclust.max_length() < max_length[np] || almost_zero(tclust.max_length() - max_length[np])) && tclust.min_length() > min_length && !contains(tclust)) {
857  at(np).push_back(GenericOrbit<ClustType>(tclust));
858  at(np).back().get_equivalent(prim.factor_group(), tol());
859  }
860  tclust.pop_back();
861  }
862  }
863  }
864  sort();
865  get_index();
866  return;
867  }
868 
869  //****************************************************************************************************************
870  //
871  // Constructs an orbitree of decorated clusters, using the prototypes of an already constructed undecorated Orbitree
872  // Uses the 'symgroup' and periodicity type 'ptype' to generate equivalent decorated clusters
873  //
874  // Generates decorations with at least one site in cluster different from the background of the prim
875  //
876  //*****************************************************************************************************************
877 
878  template<typename ClustType>
880  //std::cout << "begin generate_decorated_orbitree" << std::endl;
881 
882  PERIODICITY_MODE P(ptype);
883 
884  // copy in_tree to *this
885  *this = in_tree;
886 
887  resize(max_num_sites + 1);
888 
889  // add empty cluster
890  at(0).push_back(GenericOrbit<ClustType>(ClustType(lattice)));
891  at(0).back().get_equivalent(symgroup, tol());
892 
893  Index np, no, i;
894  //Array<Array<int> > full_decor_map;
895  Array<Array<int> > decor_map;
896 
897  // loop over OrbitBranches
898  for(np = 1; np < in_tree.size(); np++) {
899 
900  // loop over Orbits in Orbitbranch
901  for(no = 0; no < in_tree.size(np); no++) {
902 
903  //full_decor_map = in_tree.prototype(np, no).get_full_decor_map();
904  if(full_decor)
905  decor_map = in_tree.prototype(np, no).get_full_decor_map();
906  else
907  decor_map = in_tree.prototype(np, no).get_decor_map();
908 
909  // add a new Orbit for each unique decoration
910  // // exclude full_decor_map[0], since this is all background
911  // for(i = 1; i < full_decor_map.size(); i++)
912  for(i = 0; i < decor_map.size(); i++) {
913 
914  // decorate prototype
915  ClustType tclust(in_tree.prototype(np, no));
916  //tclust.decorate(full_decor_map[i]);
917  tclust.decorate(decor_map[i]);
918 
919  // add orbit
920  at(np).push_back(GenericOrbit<ClustType>(tclust));
921  at(np).back().get_equivalent(symgroup, tol());
922 
923  } // unique decorations
924 
925  } // orbits
926 
927  } // orbitbranches
928 
929  sort();
930  get_index();
931  set_lattice(lattice, COORD_MODE::CHECK());
932  //std::cout << "finish generate_decorated_orbitree" << std::endl;
933 
934  };
935 
936  //****************************************************************************************************************
937  //
938  // Constructs an orbitree of HopClusters, using the prototypes of an already constructed undecorated Orbitree
939  //
940  // ClustType must be HopCluster :: Make a derived HopOrbitree???
941  //
942  // Formula:
943  // Find unique decorations of each cluster in in_tree.
944  // Check all permutations of the decorations, find prototype HopClusters
945  // Generate HopCluster.clust_group (HopGroup), necessary for the HopCluster local orbitree
946  // For each prototype HopCluster,
947  // use the prim.factor_group() to generate equivalents on translated clusters
948  //
949  //
950  //*****************************************************************************************************************
951 
952  template<typename ClustType>
954  //std::cout << "begin generate_hop_orbitree" << std::endl;
956 
957  /*
958  {
959  std::ofstream outfile;
960  std::stringstream ss;
961  ss << "FACTORGROUP";
962  outfile.open(ss.str().c_str());
963 
964  outfile << "FACTORGROUP:" << std::endl;
965  prim.factor_group().print(outfile, COORD_DEFAULT);
966 
967 
968  outfile.close();
969  }
970  */
971 
972 
973  // copy in_tree to *this
974  this->clear();
975  this->max_num_sites = in_tree.max_num_sites;
976 
977  resize(max_num_sites + 1);
978 
979  Index np, no, nd, ii;
980  Array<Array<int> > full_decor_map;
981  std::string clean(80, ' ');
982 
983  // loop over OrbitBranches
984  // for now, assume no single site hops
985  // (examples of single site hop would be orientation flip, charge state change)
986  for(np = 2; np < in_tree.size(); np++) {
987 
988  //std::cout << "OrbitBranch " << np << std::endl;
989  // loop over Orbits in Orbitbranch
990  for(no = 0; no < in_tree.size(np); no++) {
991  std::cout << clean << '\r' << "Generate HopOrbitree branch: " << np << " orbit: " << no << "\r" << std::flush;
992  full_decor_map = in_tree.prototype(np, no).get_full_decor_map();
993 
994  // consider each unique decoration
995  // include full_decor_map[0], since all background might be an allowed hop
996  for(nd = 0; nd < full_decor_map.size(); nd++) {
997  //std::cout << " Decor " << nd << ": " << full_decor_map[nd] << std::endl;
998 
999  // create decorated SiteCluster (start point)
1000  SiteCluster sclust(in_tree.prototype(np, no));
1001  sclust.decorate(full_decor_map[nd]);
1002 
1003  // might filter decorations here.
1004  // Right now, filter to check that there is only 1 Va
1005  int Va_count = 0;
1006  for(ii = 0; ii < sclust.size(); ii++) {
1007  if(sclust[ii].is_vacant())
1008  Va_count++;
1009  }
1010 
1011  if(Va_count != 1)
1012  continue;
1013 
1014  // write undecorated site clust_group
1015  /*
1016  for(ne = 0; ne < in_tree.orbit(np, no).size(); ne++)
1017  {
1018  std::ofstream outfile;
1019  std::stringstream ss;
1020  ss << "SITECLUST." << np << "." << no << "." << ne;
1021  outfile.open(ss.str().c_str());
1022 
1023  outfile << "SITECLUSTER Branch:" << np << " Orbit: " << no << " Equiv: " << ne << std::endl;
1024  in_tree.orbit(np, no).at(ne).print_sites(outfile, 2, '\n');
1025  outfile << '\n';
1026  outfile << "CLUSTGROUP:" << std::endl;
1027  in_tree.orbit(np, no).at(ne).clust_group.print(outfile, COORD_DEFAULT);
1028 
1029 
1030  outfile.close();
1031  }
1032  */
1033 
1034  // initialize forward_permuation
1035  Array<Index> perm;
1036  for(ii = 0; ii < np; ii++) {
1037  perm.push_back(ii);
1038  }
1039 
1040  // loop over all forward_permutations
1041  do {
1042  //std::cout << " perm: " << perm << std::endl;
1043 
1044  // check that all atoms move (avoid subcluster hops)
1045  bool perm_ok = true;
1046  for(ii = 0; ii < np; ii++)
1047  if(perm[ii] == ii) {
1048  perm_ok = false;
1049  break;
1050  }
1051 
1052  if(!perm_ok)
1053  continue;
1054 
1055  // check that the permutation is allowed based on the site domains
1056  if(!ClustType::allowed(sclust, perm))
1057  continue;
1058 
1059 
1060  // if all atoms move, create a test HopCluster
1061  ClustType tclust(sclust, perm);
1062  //tclust.print_decorated_sites(std::cout, 2, '\n');
1063 
1064  // check if 'tclust' is symmetrically equivalent to an existing prototype HopCluster
1065  if(!contains(tclust)) {
1066  //std::cout << " Add orbit!" << std::endl;
1067  // if 'tclust' has not already been found
1068  at(np).push_back(GenericOrbit<ClustType>(tclust));
1069  //std::cout << " get_equivalent()" << std::endl;
1070  at(np).back().get_equivalent(prim.factor_group(), tol());
1071 
1072  // // write HopClusters & HopGroup to file
1073  // for(ne = 0; ne < at(np).back().size(); ne++)
1074  // {
1075  // std::ofstream outfile;
1076  // std::stringstream ss;
1077  // ss << "HOP." << np << "." << at(np).size() - 1 << "." << ne;
1078  // outfile.open(ss.str().c_str());
1079  //
1080  // outfile << "HOP Branch:" << np << " Orbit: " << at(np).size() - 1 << " Equiv: " << ne << std::endl;
1081  // at(np).back().at(ne).print_decorated_sites(outfile, 2, '\n');
1082  // outfile << '\n';
1083  // outfile << "HOPGROUP:" << std::endl;
1084  // at(np).back().at(ne).clust_group.print(outfile, COORD_DEFAULT);
1085  //
1086  // outfile.close();
1087  // }
1088 
1089  //std::cout << " Finish adding orbit" << std::endl;
1090 
1091  }
1092 
1093  }
1094  while(perm.next_permute());
1095 
1096  } // unique decorations
1097 
1098  } // orbits
1099 
1100  } // orbitbranches
1101 
1102  std::cout << clean << '\r' << std::flush;
1103 
1104  sort();
1105  get_index();
1106  set_lattice(lattice, COORD_MODE::CHECK());
1107  return;
1108  };
1109 
1110 
1111  //****************************************************************************************************************
1112  //
1113  // Constructs an orbitree of HopClusters, using the prototypes read from a file
1114  //
1115  // ClustType must be HopCluster
1116  //
1117  // Formula:
1118  // Read a prototype HopCluster from 'filename'
1119  // For each prototype HopCluster,
1120  // use the prim.factor_group() to generate equivalents on translated clusters
1121  // (need to use the SiteCluster.clust_group to generate equivalents on that cluster first?)
1122  //
1123  //
1124  //*****************************************************************************************************************
1125 
1126  template<typename ClustType>
1128  //std::cout << "begin generate_orbitree_from_proto_file" << std::endl;
1129  PERIODICITY_MODE P(ptype);
1130  this->clear();
1131 
1132  std::vector<std::string> s_list;
1133  std::vector<Index> n_equiv;
1134  Array<ClustType> prototype_list;
1135  ClustType tclust(lattice);
1136  Index i, j;
1137 
1139  bool SD_is_on = false;
1140 
1141 
1142  // Read the prototype file
1143  // - as going check for max number of sites in a cluster:
1144  std::ifstream file(filename);
1145  //std::cout << "begin reading file: " << filename << std::endl;
1146 
1147  COORD_MODE C(CART);
1148 
1149  this->max_num_sites = 0;
1150  //BP_Vec needs unsigned long int
1151  Index index;
1152  while(!file.eof()) {
1153  s_list.clear();
1154  std::copy(std::istream_iterator<std::string>(file),
1155  std::istream_iterator<std::string>(),
1156  std::back_inserter(s_list));
1157  if(s_list.size() == 0)
1158  continue;
1159 
1160  if(s_list[0] == "COORD_MODE") {
1161 
1162  // look for line "COORD_MODE = Direct"
1163  if(s_list[2][0] == 'D' || s_list[2][0] == 'd') {
1164  //std::cout << " set COORD_MODE = Direct" << std::endl;
1165  C.set(FRAC);
1166  }
1167  // look for line "COORD_MODE = Cartesian"
1168  else if(s_list[2][0] == 'C' || s_list[2][0] == 'c') {
1169  //std::cout << " set COORD_MODE = Cartesian" << std::endl;
1170  C.set(CART);
1171  }
1172  else {
1173  std::cerr << "Error in GenericOrbitree<ClustType>::generate_orbitree_from_proto_file()." << std::endl
1174  << " COORD_MODE not understood: " << s_list << std::endl;
1175  exit(1);
1176  }
1177  }
1178  else if(s_list.size() != (index = find_index(s_list, "Points:"))) {
1179  //std::cout << " read Points" << std::endl;
1180  Index pts = std::stol(s_list[index + 1]);
1181  if(pts > this->max_num_sites)
1182  this->max_num_sites = pts;
1183 
1184  //std::cout << " pts: " << pts << std::endl;
1185  //std::cout << " read line" << std::endl;
1186 
1187  // Read line "Prototype of X Equivalent Clusters in Orbit Y"
1188  s_list.clear();
1189  std::copy(std::istream_iterator<std::string>(file),
1190  std::istream_iterator<std::string>(),
1191  std::back_inserter(s_list));
1192 
1193  // Store the number of equivalent clusters expected
1194  n_equiv.push_back(std::stol(s_list[2]));
1195 
1196  // Read the cluster
1197  //std::cout << " read cluster" << std::endl;
1198  tclust.read(file, pts, C.check(), SD_is_on);
1199 
1200  // Add to the list of prototypes
1201  tclust.calc_properties();
1202  prototype_list.push_back(tclust);
1203  }
1204  }
1205 
1206  //std::cout << " max_num_sites = " << this->max_num_sites << std::endl;
1207  resize(max_num_sites + 1);
1208 
1209 
1210  for(i = 0; i < prototype_list.size(); i++) {
1211  //std::cout << " Add orbit!" << std::endl;
1212  at(prototype_list[i].size()).push_back(GenericOrbit<ClustType>(prototype_list[i]));
1213  //std::cout << " get_equivalent()" << std::endl;
1214  at(prototype_list[i].size()).back().get_equivalent(sym_group, tol());
1215 
1216  if(n_equiv[i] != at(prototype_list[i].size()).back().size()) {
1217  std::cerr << "Error in Orbitree::generate_orbitree_from_proto_file()." << std::endl
1218  << " Expected " << n_equiv[i] << " equivalents, but only generated " << at(prototype_list[i].size()).back().size() << " equivalents." << std::endl
1219  << " Prototype: " << std::endl;
1220  prototype_list[i].print_sites(std::cerr, 6, '\n');
1221  std::cerr << "\n" << std::endl;
1222 
1223  for(j = 0; j < at(prototype_list[i].size()).back().size(); j++) {
1224  std::cerr << " Equivalent " << j << std::endl;
1225  at(prototype_list[i].size()).back().at(j).print_sites(std::cerr, 6, '\n');
1226  }
1227  exit(1);
1228  }
1229  }
1230 
1231  set_lattice(lattice, COORD_MODE::CHECK());
1232  sort();
1233  get_index();
1234  return;
1235  };
1236 
1237 
1238  //********************************************************************
1239  //
1240  // Generates orbitree of all unique clusters within a supercell
1241  // If two clusters of the same point-size overlap, it keeps the one with shorter length
1242  //
1243  //********************************************************************
1244 
1245  template<typename ClustType>
1246  void GenericOrbitree<ClustType>::generate_in_cell(const Structure &prim, const Lattice &cell, int num_images) {
1247  Index i, j, np, no;
1248 
1250  Lattice reduced_cell(cell.get_reduced_cell());
1251 
1252  lattice = prim.lattice();
1253 
1254  PrimGrid prim_grid(lattice, reduced_cell);
1255 
1256  // make the grid from which the sites for the clusters are to be picked
1257  EigenCounter<Eigen::Vector3i > shift_count(Eigen::Vector3i::Zero(), Eigen::Vector3i::Ones(), Eigen::Vector3i::Ones());
1258  Coordinate shift(reduced_cell);
1259 
1260  do {
1261  for(i = 0; i < 3; i++)
1262  shift.frac(i) = shift_count[i];
1263 
1264  for(i = 0; i < prim.basis.size(); i++) {
1265  if(prim.basis[i].site_occupant().size() < min_num_components) continue;
1266 
1267  for(j = 0; j < prim_grid.size(); j++) {
1268  gridstruc.push_back(prim.basis[i] + prim_grid.coord(j, PRIM));
1269  // gridstruc.back().set_lattice(cell);
1270  gridstruc.back().set_lattice(reduced_cell, CART);
1271  gridstruc.back().within();
1272  gridstruc.back() -= shift;
1273  gridstruc.back().set_lattice(lattice, CART);
1274  }
1275  }
1276 
1277  }
1278  while(++shift_count);
1279 
1280 
1281  // Get orbitree ready to hold clusters.
1282  if(size())
1283  std::cerr << "WARNING: Orbitree is about to be overwritten! Execution will continue normally, but side effects may occur.\n";
1284 
1285  //Size outer array to have sufficient space to create orbitree
1286  resize(max_num_sites + 1);
1287 
1288  // Add orbit corresponding to empty cluster
1289  at(0).push_back(GenericOrbit<ClustType>(ClustType(lattice)));
1290  at(0).back().get_equivalent(prim.factor_group(), tol());
1291 
1292  //for each cluster of the previous size, add points from gridstruc
1293  // - see if the new cluster satisfies the size requirements
1294  // - see if it is new
1295  // - generate all its equivalents
1296 
1297 
1298  std::cout << "About to begin construction of non-empty clusters\n";
1299  for(np = 1; np <= max_num_sites; np++) {
1300  std::cout << "Doing np = " << np << '\n';
1301 
1302  if(size(np - 1) == 0) {
1303  std::cerr << "WARNING: Orbitree::generate_orbitree is unable to enumerate clusters of size " << np - 1 << " or larger.\n" ;
1304  get_index();
1305  sort();
1306  return;
1307  }
1308 
1309  for(no = 0; no < size(np - 1); no++) {
1310  std::cout << "Adding sites to orbit " << no << " of " << size(np - 1) << "\n";
1311 
1312  ClustType tclust(lattice);
1313  for(i = 0; i < orbit(np - 1, no).prototype.size(); i++)
1314  tclust.push_back(orbit(np - 1, no).prototype[i]);
1315 
1316 
1317  for(i = 0; i < gridstruc.size(); i++) {
1318 
1319  if(tclust.contains(gridstruc[i]))
1320  continue;
1321 
1322  tclust.push_back(gridstruc[i]);
1323 
1324  if(tclust.image_check(reduced_cell, num_images)) continue;
1325  tclust.within();
1326  tclust.calc_properties();
1327  if(!contains(tclust) && tclust.min_length() > min_length) {
1328  at(np).push_back(GenericOrbit<ClustType>(tclust));
1329  at(np).back().get_equivalent(prim.factor_group(), tol());
1330  }
1331 
1332  tclust.pop_back();
1333  }
1334  }
1335  }
1336  sort();
1337  get_index();
1338  return;
1339 
1340  }
1341 
1342  //********************************************************************
1343  //
1344  // Gets the hierarchy of the clusters.
1345  //
1346  //
1347  //********************************************************************
1348 
1349  template<typename ClustType>
1351  subcluster.clear();
1352 
1353  get_index();
1354 
1355  Array<int> tsubcluster;
1356 
1357  //make subcluster table for the empty cluster
1358  subcluster.push_back(tsubcluster);
1359 
1360  //take Cluster of size n
1361  //for each cluster of size < n in Cluster
1362  //look through Multiplet and see if there is an orbit that matches
1363  for(Index np = 1; np < size(); np++) {
1364  for(Index no = 0; no < size(np); no++) {
1365 
1366  ClustType tclust(lattice);
1367 
1368  Array<int> min(orbit(np, no).prototype.size(), 0), //All zeros
1369  max(orbit(np, no).prototype.size(), 1), //All ones
1370  inc(orbit(np, no).prototype.size(), 1); //All ones
1371 
1372  //enumerate all subclusters of cluster of orbit(np,no), represented in the Counter as 1's and 0's
1373  Counter<Array<int> > site_counter(min, max, inc);
1374  subcluster.push_back(tsubcluster);
1375  do {
1376  if(site_counter() == min || site_counter() == max) continue; //make sure you don't add the empty or full subcluster
1377 
1378  for(Index i = 0; i < site_counter().size(); i++) {
1379  if(site_counter()[i]) {
1380  tclust.push_back(orbit(np, no).prototype[i]);
1381  }
1382  }
1383 
1384  //check if tclust is in list of clusters of size tclust.size()
1385  subcluster.back().push_back(find(tclust));
1386 
1387  }
1388  while(++site_counter);
1389 
1390  }
1391  }
1392  return;
1393  }
1394 
1395 
1396 
1397  //***********************************************************
1398  //
1399  // Reads in CSPECS
1400  //
1401  // The format of CSPECS is as follows:
1402  // Description of structure/system (ignored by code)
1403  // Radius or Number
1404  // cluster size within radius size or number of clusters
1405  // 2 6.3
1406  //
1407  //
1408  //***********************************************************
1409  template<typename ClustType>
1410  void GenericOrbitree<ClustType>::read_CSPECS(std::istream &stream) {
1411 
1412  int cluster_size;
1413  int curr_cluster_size = 0;
1414  double specs;
1415  char ch, abc[256];
1416 
1417  min_num_components = 0; //added 03/23/13
1418 
1419  stream.ignore(1000, '\n');
1420  ch = stream.peek();
1421 
1422  if(ch == 'R' || ch == 'r') {
1423  max_length.clear();
1424  // For empty and point clusters;
1425 
1426 
1427  stream.ignore(1000, '\n');
1428  stream.getline(abc, 200);
1429 
1430  while(stream >> cluster_size) {
1431  if(curr_cluster_size == 0) {
1432  max_length.push_back(0.0);
1433  if(cluster_size == 1) {
1434  // LCSPECS file
1435  // do nothing
1436  max_num_sites = 0;
1437 
1438  }
1439  else if(cluster_size == 2) {
1440  // CSPECS file
1441  // push_back a max_length of
1442  max_length.push_back(0.0);
1443  max_num_sites = 1;
1444 
1445  }
1446  else {
1447  std::cerr << "error in GenericOrbitree<ClustType>::read_CSPECS()" << std::endl
1448  << " Your CSPECS file is wrong. The first cluster size is: " << cluster_size << std::endl
1449  << " It should be 1 (for local) or 2 (for global)" << std::endl;
1450  std::exit(1);
1451  }
1452  }
1453  curr_cluster_size = cluster_size;
1454 
1455  stream >> specs;
1456  max_length.push_back(specs);
1457  max_num_sites++; //added 10/25/12
1458  stream.getline(abc, 200);
1459 
1460  }
1461  }
1462  else if(ch == 'N' || ch == 'n') {
1463  num_clusts.clear();
1464 
1465  //TODO: necessary to push back for empty and point clusters?
1466 
1467  stream.ignore(1000, '\n');
1468 
1469  while(stream >> cluster_size) {
1470  stream >> specs;
1471  num_clusts.push_back(specs);
1472  stream.ignore(1000, '\n');
1473  }
1474  }
1475  else {
1476  std::cerr << "ERROR in 2nd line of CSPECS. 2nd line should indicate either Radius or Number.\n";
1477  exit(1);
1478  }
1479 
1480  };
1481 
1482  //*********************************
1483 
1484  template<typename ClustType>
1485  void GenericOrbitree<ClustType>::print(std::ostream &stream) const {
1486 
1487  print_proto_clust(stream);
1488 
1489  /*
1490  for(Index i = 0; i < size(); i++) { //Loops over outer array (point/pair/triplet arrays)
1491 
1492  for(Index j = 0; j < size(i); j++) { //Loops over each Orbit, j, with Clusters of size i
1493  stream.width(5);
1494  stream << index[i][j];
1495  stream.width(5);
1496 
1497  stream << orbit(i, j).prototype.size();
1498  stream.width(5); //Size of Cluster
1499 
1500  stream << orbit(i, j).size() << std::endl; //Multiplicity
1501 
1502  orbit(i, j).prototype.print(stream); //Prints coordinates from Cluster::print() for the prototype cluster (which prints from Site::print() )
1503  stream << std::endl;
1504  };
1505  };
1506  */
1507  };
1508 
1509  //John G 011013
1510  //***********************************************
1511  //
1512  // Assignment operator
1513  //
1514  //***********************************************
1515  template<typename ClustType>
1517  //clear();
1518  //set_lattice(RHS.lattice, FRAC);
1519 
1520  //copy members
1521  lattice = RHS.lattice;
1522  max_num_sites = RHS.max_num_sites;
1523  min_num_components = RHS.min_num_components;
1524  max_length = RHS.max_length;
1525  min_length = RHS.min_length;
1526  num_clusts = RHS.num_clusts;
1527  index_to_row = RHS.index_to_row;
1528  index_to_column = RHS.index_to_column;
1529  index = RHS.index;
1530  Norbits = RHS.Norbits;
1531  subcluster = RHS.subcluster;
1532  m_bspecs = RHS.bspecs();
1533  m_b2asym = RHS.m_b2asym;
1534 
1535  //copy all orbitbranches over
1536  m_asym_unit = RHS._asym_unit();
1537  m_asym_unit.set_lattice(lattice, CART);
1538  for(Index b = 0; b < RHS.size(); b++) {
1539  push_back(RHS[b]);
1540  }
1541 
1542  return *this;
1543  }
1544 
1545 
1546 
1547  //***********************************************
1551  //***********************************************
1552  template<typename ClustType>
1553  std::ostream &operator<< (std::ostream &stream, const GenericOrbitree<ClustType> &orbitree) {
1554  orbitree.print(stream);
1555  return stream;
1556  };
1557 
1558 
1559  //***********************************************
1560 
1561  template<typename ClustType>
1562  void GenericOrbitree<ClustType>::write_full_clust(std::string file) const {
1563  //Prints out all equivalent clusters including the prototype cluster (FPCLUST file)
1564  // Calls ClustType.print_sites() to print each cluster
1565 
1566  std::ofstream out;
1567  out.open(file.c_str());
1568  if(!out) {
1569  std::cerr << "Can't open" << file << ".\n";
1570  return;
1571  }
1572 
1573  print_full_clust(out);
1574  };
1575 
1576  //***********************************************
1577 
1578  template<typename ClustType>
1579  void GenericOrbitree<ClustType>::write_proto_clust(std::string file) const {
1580  //Prints out all prototype clusters (CLUST file)
1581  // Calls ClustType.print_sites() to print each prototype cluster
1582 
1583  std::ofstream out;
1584  out.open(file.c_str());
1585  if(!out) {
1586  std::cerr << "Can't open" << file << ".\n";
1587  return;
1588  }
1589 
1590  print_proto_clust(out);
1591  };
1592 
1593  //***********************************************
1594 
1595  template<typename ClustType>
1597  //Prints out all equivalent clusters including the prototype cluster (FPCLUST file)
1598  // Calls ClustType.print_sites() to print each cluster
1599 
1600 
1601  std::ofstream out;
1602  out.open(file.c_str());
1603  if(!out) {
1604  std::cerr << "Can't open" << file << ".\n";
1605  return;
1606  }
1607 
1608  print_full_decorated_clust(out);
1609  };
1610 
1611  //***********************************************
1612 
1613  template<typename ClustType>
1615  //Prints out all prototype clusters (CLUST file)
1616 
1617  std::ofstream out;
1618  out.open(file.c_str());
1619  if(!out) {
1620  std::cerr << "Can't open" << file << ".\n";
1621  return;
1622  }
1623 
1624  print_proto_decorated_clust(out);
1625  };
1626 
1627  //***********************************************
1628 
1629  template<typename ClustType>
1630  void GenericOrbitree<ClustType>::print_full_clust(std::ostream &out) const {
1631  //Prints out all equivalent clusters including the prototype cluster (FPCLUST file)
1632  // Calls ClustType.print_sites() to print each cluster
1633 
1634  if(index.size() != size()) get_index();
1635 
1636  out << "COORD_MODE = " << COORD_MODE::NAME() << std::endl << std::endl;
1637 
1638  out.flags(std::ios::showpoint | std::ios::fixed | std::ios::left);
1639  out.precision(5);
1640 
1641  for(Index i = 0; i < size(); i++) {
1642  if(size(i) != 0) out << "** Branch " << i << " ** \n" << std::flush;
1643  for(Index j = 0; j < size(i); j++) { //Loops over all i sized Orbits
1644  out << " ** " << index[i][j] << " of " << Norbits << " Orbits **"
1645  << " Orbit: " << i << " " << j
1646  << " Points: " << orbit(i, j).prototype.size()
1647  << " Mult: " << orbit(i, j).size()
1648  << " MinLength: " << orbit(i, j).prototype.min_length()
1649  << " MaxLength: " << orbit(i, j).prototype.max_length()
1650  << '\n' << std::flush;
1651 
1652  for(Index k = 0; k < orbit(i, j).size(); k++) { // Loops over each equivalent cluster in j
1653  out << " " << k << " of " << orbit(i, j).size() << " Equivalent Clusters in Orbit " << index[i][j] << '\n' << std::flush;
1654  orbit(i, j).at(k).print_sites(out, 18, '\n');
1655  }
1656  out << '\n' << std::flush;
1657  }
1658  if(size(i) != 0) out << '\n' << std::flush;
1659  }
1660  };
1661 
1662  //***********************************************
1663 
1664 
1665  template<typename ClustType>
1667  //Prints out all equivalent clusters including the prototype cluster (FPCLUST file)
1668  // Calls ClustType.print_sites() to print each cluster
1669 
1670  if(index.size() != size()) get_index();
1671 
1672  out << "COORD_MODE = " << COORD_MODE::NAME() << std::endl << std::endl;
1673 
1674  out.flags(std::ios::showpoint | std::ios::fixed | std::ios::left);
1675  out.precision(5);
1676 
1677  for(Index i = 0; i < size(); i++) {
1678  if(size(i) != 0) out << "** Branch " << i << " ** \n" << std::flush;
1679  for(Index j = 0; j < size(i); j++) { //Loops over all i sized Orbits
1680  out << " ** " << index[i][j] << " of " << Norbits << " Orbits **"
1681  << " Orbit: " << i << " " << j
1682  << " Points: " << orbit(i, j).prototype.size()
1683  << " Mult: " << orbit(i, j).size()
1684  << " MinLength: " << orbit(i, j).prototype.min_length()
1685  << " MaxLength: " << orbit(i, j).prototype.max_length()
1686  << '\n' << std::flush;
1687 
1688  for(Index k = 0; k < orbit(i, j).size(); k++) { // Loops over each equivalent cluster in j
1689  out << " " << k << " of " << orbit(i, j).size() << " Equivalent Clusters in Orbit " << index[i][j] << '\n' << std::flush;
1690  orbit(i, j).at(k).print_basis_info(out, 18, '\n');
1691  }
1692  out << '\n' << std::flush;
1693  }
1694  if(size(i) != 0) out << '\n' << std::flush;
1695  }
1696  };
1697 
1698  //***********************************************
1699 
1700  template<typename ClustType>
1701  void GenericOrbitree<ClustType>::print_proto_clust(std::ostream &out) const {
1702  //Prints out all prototype clusters (CLUST file)
1703  // Calls ClustType.print_sites() to print each prototype cluster
1704 
1705  if(index.size() != size()) get_index();
1706 
1707  out << "COORD_MODE = " << COORD_MODE::NAME() << std::endl << std::endl;
1708 
1709  out.flags(std::ios::showpoint | std::ios::fixed | std::ios::left);
1710  out.precision(5);
1711 
1712  for(Index i = 0; i < size(); i++) {
1713  if(size(i) != 0) out << "** Branch " << i << " ** \n" << std::flush;
1714  for(Index j = 0; j < size(i); j++) { //Loops over all i sized Orbits
1715  out << " ** " << index[i][j] << " of " << Norbits << " Orbits **"
1716  << " Orbit: " << i << " " << j
1717  << " Points: " << orbit(i, j).prototype.size()
1718  << " Mult: " << orbit(i, j).size()
1719  << " MinLength: " << orbit(i, j).prototype.min_length()
1720  << " MaxLength: " << orbit(i, j).prototype.max_length()
1721  << '\n' << std::flush;
1722 
1723  if(orbit(i, j).size() > 0) {
1724  for(int k = 0; k < 1; k++) { // Loops over each equivalent cluster in j
1725  out << " " << "Prototype" << " of " << orbit(i, j).size() << " Equivalent Clusters in Orbit " << index[i][j] << '\n' << std::flush;
1726  orbit(i, j).at(k).print_sites(out, 18, '\n');
1727 
1728  }
1729  }
1730  out << '\n' << std::flush;
1731  }
1732  if(size(i) != 0) out << '\n' << std::flush;
1733  }
1734  };
1735  //***********************************************
1736 
1737  template<typename ClustType>
1739  //Prints out all prototype clusters (CLUST file)
1740  // Calls ClustType.print_clust_basis() to print each prototype cluster
1741 
1742  if(index.size() != size()) get_index();
1743 
1744  out << "COORD_MODE = " << COORD_MODE::NAME() << std::endl << std::endl;
1745 
1746  out.flags(std::ios::showpoint | std::ios::fixed | std::ios::left);
1747  out.precision(5);
1748 
1749  for(Index no = 0; no < asym_unit().size(); no++) {
1750  out << "Asymmetric unit " << no + 1 << ":\n";
1751  for(Index ne = 0; ne < asym_unit()[no].size(); ne++) {
1752  Index b = asym_unit()[no][ne][0].basis_ind();
1753  out << " Basis site " << b << ":\n"
1754  << " ";
1755  asym_unit()[no][ne][0].print(out);
1756  out << "\n";
1757  if(asym_unit()[no][ne].clust_basis.size() == 0)
1758  out << " [No site basis functions]\n\n";
1759  for(Index f = 0; f < asym_unit()[no][ne].clust_basis.size(); f++) {
1760  for(Index s = 0; s < asym_unit()[no][ne][0].site_occupant().size(); s++) {
1761  if(s == 0)
1762  out << " ";
1763  out << " \\phi_" << b << '_' << f << '[' << asym_unit()[no][ne][0].site_occupant()[s].name << "] = "
1764  << asym_unit()[no][ne].clust_basis[f]->eval(Array<Index>(1, asym_unit()[no][ne][0].site_occupant().ID()), Array<Index>(1, s));
1765  if(s + 1 == asym_unit()[no][ne][0].site_occupant().size())
1766  out << "\n";
1767  else
1768  out << ", ";
1769  }
1770  }
1771  }
1772  }
1773  out << "\n\n";
1774  Index nf = 0;
1775  for(Index i = 0; i < size(); i++) {
1776  if(size(i) != 0) out << "** Branch " << i << " ** \n" << std::flush;
1777  for(Index j = 0; j < size(i); j++) { //Loops over all i sized Orbits
1778  out << " ** " << index[i][j] << " of " << Norbits << " Orbits **"
1779  << " Orbit: " << i << " " << j
1780  << " Points: " << orbit(i, j).prototype.size()
1781  << " Mult: " << orbit(i, j).size()
1782  << " MinLength: " << orbit(i, j).prototype.min_length()
1783  << " MaxLength: " << orbit(i, j).prototype.max_length()
1784  << '\n' << std::flush;
1785 
1786  out << " " << "Prototype" << " of " << orbit(i, j).size() << " Equivalent Clusters in Orbit " << index[i][j] << '\n' << std::flush;
1787  prototype(i, j).print_clust_basis(out, nf, 8, '\n');
1788  nf += prototype(i, j).clust_basis.size();
1789  out << "\n\n" << std::flush;
1790  }
1791  if(size(i) != 0) out << '\n' << std::flush;
1792  }
1793  };
1794 
1795  //***********************************************
1796 
1797  template<typename ClustType>
1799  //Prints out all equivalent clusters including the prototype cluster (FPCLUST file)
1800  // Calls ClustType.print_sites() to print each cluster
1801 
1802  if(index.size() != size()) get_index();
1803 
1804  out << "COORD_MODE = " << COORD_MODE::NAME() << std::endl << std::endl;
1805 
1806  out.flags(std::ios::showpoint | std::ios::fixed | std::ios::left);
1807  out.precision(5);
1808 
1809  for(Index i = 0; i < size(); i++) {
1810  if(size(i) != 0) out << "** Branch " << i << " ** \n" << std::flush;
1811  for(Index j = 0; j < size(i); j++) { //Loops over all i sized Orbits
1812  out << " ** " << index[i][j] << " of " << Norbits << " Orbits **"
1813  << " Orbit: " << i << " " << j
1814  << " Points: " << orbit(i, j).prototype.size()
1815  << " Mult: " << orbit(i, j).size()
1816  << " MinLength: " << orbit(i, j).prototype.min_length()
1817  << " MaxLength: " << orbit(i, j).prototype.max_length()
1818  << '\n' << std::flush;
1819  for(Index k = 0; k < orbit(i, j).size(); k++) { // Loops over each equivalent cluster in j
1820  out << " " << k << " of " << orbit(i, j).size() << " Equivalent Clusters in Orbit " << index[i][j] << '\n' << std::flush;
1821  orbit(i, j).at(k).print_decorated_sites(out, 18, '\n');
1822  }
1823  out << '\n' << std::flush;
1824  }
1825  if(size(i) != 0) out << '\n' << std::flush;
1826  }
1827  };
1828 
1829  //***********************************************
1830 
1831  template<typename ClustType>
1833  //Prints out all decorated prototype clusters (like BCLUST file)
1834 
1835  if(index.size() != size()) get_index();
1836 
1837  out << "COORD_MODE = " << COORD_MODE::NAME() << std::endl << std::endl;
1838 
1839  out.flags(std::ios::showpoint | std::ios::fixed | std::ios::left);
1840  out.precision(5);
1841 
1842  for(Index i = 0; i < size(); i++) {
1843  if(size(i) != 0) out << "** Branch " << i << " ** \n" << std::flush;
1844  for(Index j = 0; j < size(i); j++) { //Loops over all i sized Orbits
1845  out << " ** " << index[i][j] << " of " << Norbits << " Orbits **"
1846  << " Orbit: " << i << " " << j
1847  << " Points: " << orbit(i, j).prototype.size()
1848  << " Mult: " << orbit(i, j).size()
1849  << " MinLength: " << orbit(i, j).prototype.min_length()
1850  << " MaxLength: " << orbit(i, j).prototype.max_length()
1851  << '\n' << std::flush;
1852 
1853  if(orbit(i, j).size() > 0) {
1854  for(int k = 0; k < 1; k++) { // Loops over each equivalent cluster in j
1855  out << " " << "Prototype" << " of " << orbit(i, j).size() << " Equivalent Clusters in Orbit " << index[i][j] << '\n' << std::flush;
1856  orbit(i, j).at(k).print_decorated_sites(out, 18, '\n');
1857 
1858  }
1859  }
1860 
1861  out << '\n' << std::flush;
1862  }
1863  if(size(i) != 0) out << '\n' << std::flush;
1864  }
1865  };
1866 
1867 
1868  //John G 050513
1869  //************************************************************
1877  //************************************************************
1878 
1879  template<typename ClustType> template<class PhenomType>
1880  void GenericOrbitree<ClustType>::generate_local_orbitree(const Structure &prim, const PhenomType &tmp_phenom_clust,
1881  bool include_phenom_clust_sites) {
1882  //std::cout << "\n\nBegin generate_local_orbitree() --------------\n\n" << std::flush;
1883 
1887 
1888  //std::cout << "phenom_clust: " << std::endl;
1889  //phenom_clust.print_v2(std::cout);
1890 
1891  PhenomType phenom_clust(tmp_phenom_clust);
1892 
1893  //std::cout << "phenom_clust: " << std::endl;
1894  //phenom_clust.print_v2(std::cout);
1895 
1896 
1897  Index i, j, np, no;
1898  Eigen::Vector3i dim; //size of gridstruc
1899  double dist, max_dist;
1901 
1902  lattice = prim.lattice();
1903  Coordinate lat_point(lattice);
1904 
1905 
1906  // Make 'basis', a list of the basis sites in prim that we want to make clusters from
1907  //std::cout << "Finding Basis:\n" << std::flush;
1908  for(i = 0; i < prim.basis.size(); i++) {
1909  if(prim.basis[i].site_occupant().size() >= min_num_components) {
1910  basis.push_back(prim.basis[i]);
1911  basis.back().set_lattice(lattice, CART);
1912  }
1913  }
1914 
1915 
1916  // Make 'gridstruc', a list of all the sites we might make clusters from
1917 
1918  // 'max_radius' is the maximum distance from any of the sites in 'phenom_clust' for sites in the local clusters
1919  double max_radius = max_length.max();
1920 
1921  // 'dim' is size of grid so that all sites within max_radius are included
1922  dim = lattice.enclose_sphere(max_radius);
1923  EigenCounter<Eigen::Vector3i > grid_count(-dim, dim, Eigen::Vector3i::Ones());
1924  //std::cout << "dim is " << dim << '\n' << std::flush;
1925  //std::cout << "\n Finding Grid_struc:\n" << std::flush;
1926 
1927  // check all sites to see if they are close enough to 'phenom_clust' that they might be included in the local clusters
1928  do {
1929  lat_point.frac() = grid_count().cast<double>();
1930 
1931  for(i = 0; i < basis.size(); i++) {
1932  // check site at basis[i] + lat_point
1933  typename ClustType::WhichCoordType tatom(basis[i] + lat_point);
1934 
1935  // don't add sites that are a part of the cluster
1936  // site occupant makes this comparison work incorrectly, so check with min_length instead
1937  //if(!include_phenom_clust_sites) if(phenom_clust.contains(tatom)) continue;
1938  if(!include_phenom_clust_sites) {
1939  bool point_is_in_phenom = false;
1940 
1941  for(Index j = 0; j < phenom_clust.size(); j++) {
1942  if(phenom_clust[j].Coordinate::operator==(tatom)) {
1943  point_is_in_phenom = true;
1944  break;
1945  }
1946  }
1947 
1948  if(point_is_in_phenom)
1949  continue;
1950  }
1951 
1952 
1953  // get distance to farthest site in the cluster
1954  max_dist = 0;
1955  for(j = 0; j < phenom_clust.size(); j++) {
1956  dist = tatom.dist(phenom_clust[j]);
1957  if(dist > max_dist)
1958  max_dist = dist;
1959  }
1960 
1961  // if that distance is less than max_radius, include it in the gridstruc
1962  if(max_dist < max_radius) {
1963  gridstruc.push_back(tatom);
1964  //std::cout << "i: " << gridstruc.size() << " " << tatom; // << std::endl;
1965  }
1966  }
1967 
1968  }
1969  while(++grid_count);
1970  //std::cout << "Finished finding grid_struc\n" << std::flush;
1971 
1972  // Get orbitree ready to hold clusters.
1973  if(size())
1974  std::cerr << "WARNING: Orbitree is about to be overwritten! Execution will continue normally, but side effects may occur.\n" << std::flush;
1975 
1976  //Size outer array (# of sites in cluster) to have sufficient space to create orbitree
1977  resize(max_num_sites + 1);
1978 
1979 
1980  //for each cluster of the previous size, add points from gridstruc
1981  // - see if the new cluster satisfies the size requirements
1982  // - see if it is new
1983  // - generate all its equivalents
1984 
1985  //std::cout << "About to begin construction of non-empty clusters\n" << std::flush;
1986 
1987 
1988  // we want to find equivalent clusters by using the cluster group of the 'phenom_clust'
1989  // maybe don't need this, phenom_clust likely already has cluster group calculated...
1990 
1991  {
1992  PERIODICITY_MODE periodicity_mode1(PERIODIC);
1993  phenom_clust.get_clust_group(prim.factor_group());
1994  }
1995 
1996  // write phenom_clust to check clust group
1997  //{
1998  // std::ofstream outfile;
1999  // std::stringstream ss;
2000  // ss << "PHENOM";
2001  // outfile.open(ss.str().c_str());
2002  //
2003  // outfile << "PHENOM" << std::endl;
2004  // phenom_clust.print_decorated_sites(outfile, 2, '\n');
2005  // outfile << '\n';
2006  // outfile << "CLUSTGROUP:" << std::endl;
2007  // phenom_clust.clust_group.print(outfile, COORD_DEFAULT);
2008  //
2009  //
2010  // outfile.close();
2011  // int pause;
2012  // std::cout << "Pause: " ;
2013  // std::cin >> pause;
2014  // std::cout << std::endl;
2015  //}
2016 
2017 
2018  // for local clusters, we want the PERIODICITY_MODE to be LOCAL
2019  PERIODICITY_MODE periodicity_mode2(LOCAL);
2020  //std::cout << " PMODE: " << PERIODICITY_MODE::CHECK() << endl;
2021 
2022  // Add orbit corresponding to empty cluster
2023  at(0).push_back(GenericOrbit<ClustType>(ClustType(lattice)));
2024  at(0).back().get_equivalent(phenom_clust.clust_group, tol());
2025 
2026  // loop through OrbitBranches of Orbits of clusters of np sites
2027  for(np = 1; np <= max_num_sites; np++) {
2028  //std::cout << "OrbitBranch: " << np << "\n" << std::flush;
2029 
2030  if(size(np - 1) == 0) {
2031  std::cerr << "WARNING: Orbitree::generate_local_orbitree is unable to enumerate clusters of size " << np << ".\n";
2032  std::cerr << " found no clusters of size " << np - 1 << ".\n" << std::flush;
2033  sort();
2034  get_index();
2035  //print(std::cout);
2036  return;
2037  //exit(1);
2038  }
2039 
2040  // loop through all orbits of the previous size
2041  for(no = 0; no < size(np - 1); no++) {
2042  //std::cout << " Adding sites to orbit " << no << " of " << size(np - 1) << "\n" << std::flush;
2043 
2044  // base test clust on prototype cluster of smaller size
2045  ClustType tclust(lattice);
2046  for(i = 0; i < orbit(np - 1, no).prototype.size(); i++)
2047  tclust.push_back(orbit(np - 1, no).prototype[i]);
2048 
2049  // check all sites in gridstruc
2050  for(i = 0; i < gridstruc.size(); i++) {
2051 
2052  if(tclust.contains(gridstruc[i]))
2053  continue;
2054 
2055  // add a site to the test clust
2056  tclust.push_back(gridstruc[i]);
2057 
2058 #ifdef DEBUG
2059  std::cout << "tclust is \n" << tclust << "\n" << std::flush;
2060 #endif //DEBUG
2061 
2062  //tclust.within(); // don't 'within' for local cluster
2063 
2064  // calculate lengths between sites in tclust and phenom_clust
2065  // set max_length to maximum distance between cluster sites or phenom_clust sites
2066  // set min_length to minimum distance between clusters sites (does not include phenom sites)
2067  tclust.calc_properties(phenom_clust);
2068 
2069  //std::cout << "tclust: " << std::endl;
2070  //tclust.print_v2(std::cout);
2071  //std::cout<< " tclust.max_length(): " << tclust.max_length() << " limit: " << max_length[np] << std::endl;
2072  //std::cout<< " tclust.min_length(): " << tclust.min_length() << " limit: " << min_length << std::endl;
2073  //std::cout<< " !contains(tclust): " << !contains(tclust) << std::endl;
2074 
2075 
2076 #ifdef DEBUG
2077  std::cout << "tclust is \n" << tclust << "\n" << std::flush;
2078 #endif //DEBUG
2079 
2080  if(np == 1 && !contains(tclust)) {
2081  //std::cout << "-- add point cluster" << std::endl << std::endl;
2082  at(np).push_back(GenericOrbit<ClustType>(tclust));
2083  at(np).back().get_equivalent(phenom_clust.clust_group, tol());
2084  }
2085  else if(tclust.max_length() < max_length[np] && tclust.min_length() > min_length && !contains(tclust)) {
2086  //std::cout << "-- Found a new cluster.... adding to Orbitree!\n" << std::flush;
2087  //std::cout << " The minimum length is " << min_length << "\n" << std::flush;
2088  at(np).push_back(GenericOrbit<ClustType>(tclust));
2089 
2090 #ifdef DEBUG
2091  std::cout << "The tclust we pushed back is \n" << tclust << "\n" << std::flush;
2092 #endif //DEBUG
2093 
2094  at(np).back().get_equivalent(phenom_clust.clust_group, tol());
2095  }
2096 
2097  tclust.pop_back();
2098  }
2099  }
2100  }
2101  sort();
2102  get_index();
2103  return;
2104  }
2105 
2106 
2107  //************************************************************
2108  //
2109  // Apply symmetry to every orbit in orbitree
2110  //
2111  template<typename ClustType>
2113  for(Index i = 0; i < size(); i++) {
2114  for(Index j = 0; j < size(i); j++) {
2115  orbit(i, j).apply_sym(op);
2116  }
2117  }
2118  }
2119 
2120  //************************************************************
2121 
2122  template<typename ClustType>
2123  void GenericOrbitree<ClustType>::write_eci_in(std::string filename) const {
2124  std::ofstream file(filename);
2125 
2126  print_eci_in(file);
2127 
2128  }
2129 
2130  //************************************************************
2131 
2132  template<typename ClustType>
2133  void GenericOrbitree<ClustType>::print_eci_in(std::ostream &out) const {
2134  if(index.size() != size()) get_index();
2135  if(subcluster.size() != size()) get_hierarchy();
2136 
2137  out << std::left
2138  << std::setw(8) << "label"
2139  << std::setw(8) << "weight"
2140  << std::setw(8) << "mult"
2141  << std::setw(8) << "size"
2142  << std::setw(12) << "length"
2143  << std::setw(8) << "hierarchy" << std::endl;
2144 
2145 
2146  int clustcount = 0;
2147  for(Index i = 0; i < size(); i++) {
2148  for(Index j = 0; j < size(i); j++) {
2149 
2150  for(Index k = 0; k < prototype(i, j).clust_basis.size(); k++, clustcount++) {
2151 
2152  out << std::left
2153  //<< std::setw(8) << index[i][j]
2154  << std::setw(8) << clustcount
2155  << std::setw(8) << 0
2156  << std::setw(8) << orbit(i, j).size()
2157  << std::setw(8) << orbit(i, j).prototype.size()
2158  << std::setw(12) << orbit(i, j).prototype.max_length();
2159 
2160  // print hierarchy
2161  out << std::left << std::setw(8) << 0;
2162  for(Index l = 0; l < subcluster[ index[i][j]].size(); l++) {
2163  out << std::left
2164  << std::setw(8) << subcluster[ index[i][j] ][l];
2165  }
2166  out << '\n' << std::flush;
2167  }
2168 
2169  }
2170  }
2171 
2172  //std::cout << "finish print_eci_in" << std::endl;
2173 
2174  }
2175 
2176  //********************************************************************
2177  /*
2178  template<typename ClustType>
2179  jsonParser &GenericOrbitree<ClustType>::to_json(jsonParser &json) const {
2180  json.put_obj();
2181 
2182  // template<typename ClustType>
2183  // class GenericOrbitree : public Array< GenericOrbitBranch<ClustType> >
2184  json["branches"].put_array(size());
2185  for(Index i = 0; i < size(); i++) {
2186  json["branches"][i] = at(i);
2187  }
2188 
2189  // Lattice lattice;
2190  json["lattice"] = lattice;
2191 
2192  // int max_num_sites, min_num_components;
2193  json["max_num_sites"] = max_num_sites;
2194  json["min_num_components"] = min_num_components;
2195 
2196  // Array<double> max_length;
2197  json["max_length"] = max_length;
2198 
2199  // double min_length;
2200  json["min_length"] = min_length;
2201 
2202  // Array<int> num_clusts;
2203  json["num_clusts"] = num_clusts;
2204 
2205  // mutable Array<int> index_to_row, index_to_column;
2206  json["index_to_row"] = index_to_row;
2207  json["index_to_column"] = index_to_column;
2208 
2209  // mutable Array< Array<int> > index;
2210  json["index"] = index;
2211 
2212  // mutable int Norbits;
2213  json["Norbits"] = Norbits;
2214 
2215  // mutable Array< Array<int> > subcluster;
2216  json["subcluster"] = subcluster;
2217  return json;
2218 
2219  }
2220  */
2221  //*********************************************************
2222  /*
2223  WARNING: Ensure that you have initialized the basis set
2224  in ref_struc.basis[i]
2225  */
2226  //*********************************************************
2227  template<typename ClustType>
2228  void GenericOrbitree<ClustType>::read_orbitree_from_json(const std::string &json_file_name, const SymGroup &sym_group, const Structure &ref_struc) {
2229  jsonParser json(json_file_name);
2230  (*this).from_json(json);
2231  //Check if the basis set has been initialized in ref_struc
2232  bool basis_set_init = true;
2233  int np, no;
2234  std::cout << "In read_orbitree_from_json. Initializing the occupant basis" << std::endl;
2235  if(basis_set_init) {
2236  //std::cout<<"basis_set_init is true"<<std::endl;
2237  //Set the basis sets for all the prototype clusters
2238  for(np = 0; np < (*this).size(); np++) {
2239  for(no = 0; no < at(np).size(); no++) {
2240  //std::cout<<"Working on np:"<<np<<" no:"<<no<<std::endl;
2241  at(np).at(no).prototype.update_data_members(ref_struc);
2242  }
2243  }
2244  }
2245  //Gets the equivalent clusters and the cluster symmetry
2246  for(np = 0; np < (*this).size(); np++) {
2247  for(no = 0; no < at(np).size(); no++) {
2248  at(np).at(no).get_equivalent(sym_group, tol());
2249  // std::cout<<"Sym Group of np: "<<np<<" no:"<<no<<std::endl;
2250  // at(np).at(no).prototype.clust_group.print(std::cout,FRAC);
2251  // std::cout<<"Permute group of the same"<<std::endl;
2252  // at(np).at(no).prototype.permute_group.print_permutation(std::cout);
2253  }
2254  }
2255  }
2256 
2257 
2277  template<typename ClustType>
2278  bool GenericOrbitree<ClustType>::read_custom_clusters_from_json(const jsonParser &json, const Structure &struc, const SymGroup &sym_group, bool verbose) {
2279 
2280  // Initializing data
2281  Array<ClustType> proto_clust;
2282 
2283  const jsonParser &orbit_specs = json;
2284 
2285  //proto_clust.resize(json["clusters"].size(), temp_clust);
2286  for(int i = 0; i < orbit_specs.size(); i++) {
2287 
2288  std::string in_mode = orbit_specs[i]["coordinate_mode"].template get<std::string>();
2289 
2290  COORD_TYPE json_coord_mode;
2291  if(in_mode == "Cartesian") {
2292  json_coord_mode = CART;
2293  }
2294  else if(in_mode == "Direct" || in_mode == "Fractional") {
2295  json_coord_mode = FRAC;
2296  }
2297  else if(in_mode != "Integral") {
2298  std::cerr << "ERROR in GenericOrbitree<ClustType>::read_custom_clusters_from_json. "
2299  << "The specified coord_mode for custom orbit " << i << " is invalid." << std::endl;
2300  std::cerr << "Prototype: \n" << orbit_specs[i] << std::endl;
2301  std::cerr << "coordinate_mode: " << in_mode << std::endl;
2302  std::cerr << "Valid options are: 'Cartesian', 'Direct', or 'Fractional'" << std::endl;
2303  throw std::runtime_error(
2304  "ERROR in GenericOrbitree<ClustType>::read_custom_clusters_from_json\n"
2305  " Invalid: \"coordinate_mode\": Expected one of \"Fractional\", \"Direct\", or \"Cartesian\""
2306  );
2307  }
2308 
2309  const jsonParser &proto_json = orbit_specs[i]["prototype"];
2310  ClustType temp_clust(lattice);
2311  if(in_mode == "Integral") {
2312  for(int j = 0; j < proto_json.size(); j++) {
2313  temp_clust.push_back(struc.get_site(proto_json[j].get<UnitCellCoord>()));
2314  }
2315  }
2316  else {
2317 
2318  Eigen::MatrixXd coords_as_rows;
2319  CASM::from_json(coords_as_rows, proto_json);
2320  //std::cout << "coords_as_rows is:\n" << coords_as_rows << "\n";
2321 
2322  //Looking for the correct sites in the PRIM and loading in the correct information
2323  for(int j = 0; j < coords_as_rows.rows(); j++) {
2324  //Converting to a Coordinate
2325  Coordinate tcoord(coords_as_rows.row(j).transpose(), struc.lattice(), json_coord_mode);
2326  //std::cout << "tcoord FRAC is " << tcoord.const_frac().transpose() << "\n";
2327  //std::cout << "tcoord CART is " << tcoord.const_cart().transpose() << "\n";
2328  int site_loc = struc.find(tcoord);
2329  if(site_loc != struc.basis.size()) {
2330  temp_clust.push_back(struc.basis[site_loc]);
2331  //std::cout << "back before: " << temp_clust.back().const_cart() << "\n\n";
2332  temp_clust.back().cart() = tcoord.cart();
2333  //std::cout << "back after: " << temp_clust.back().const_cart() << "\n\n";
2334  }
2335  else {
2336  std::cerr << "ERROR in GenericOrbitree<ClustType>::read_custom_clusters_from_json. "
2337  << "Coordinate in custom orbit " << i << " does not match any site in the prim." << std::endl;
2338  std::cerr << "Prototype: \n" << orbit_specs[i] << std::endl;
2339  std::cerr << "coordinate_mode: " << in_mode << std::endl;
2340  if(json_coord_mode == FRAC)
2341  std::cerr << "Could not find: " << tcoord.const_frac() << std::endl;
2342  else
2343  std::cerr << "Could not find: " << tcoord.const_cart() << std::endl;
2344  throw std::runtime_error(
2345  "ERROR in GenericOrbitree<ClustType>::read_custom_clusters_from_json\n"
2346  " Coordinate does not match any site in the prim."
2347  );
2348  }
2349  }
2350  //std::cout << "Finished reading cluster \n";
2351  //temp_clust.print(std::cout);
2352  //std::cout << "\n";
2353  }
2354  temp_clust.calc_properties();
2355  proto_clust.push_back(temp_clust);
2356  }
2357 
2358  //Add the empty cluster if the Orbitree is empty
2359  if(this->size() == 0) {
2360  (*this).push_back(GenericOrbitBranch<ClustType>(lattice));
2361  }
2362 
2363  // update max_num_sites / min_num_components based on custom input
2364  for(int i = 0; i < proto_clust.size(); i++) {
2365  if(proto_clust[i].size() > max_num_sites)
2366  max_num_sites = proto_clust[i].size();
2367  for(int j = 0; j < proto_clust[i].size(); j++) {
2368  if(proto_clust[i][j].allowed_occupants().size() < min_num_components)
2369  min_num_components = proto_clust[i][j].allowed_occupants().size();
2370  }
2371  }
2372 
2373  while(size() <= max_num_sites) {
2374  push_back(GenericOrbitBranch<ClustType>(lattice));
2375  }
2376 
2377  for(int i = 0; i < proto_clust.size(); i++) {
2378  //std::cout << "Working on cluster: " << i << std::endl;
2379  if(contains(proto_clust[i])) {
2380  std::cerr << "Proto_clust: " << std::endl;
2381  proto_clust[i].print(std::cout);
2382  std::cerr << "This cluster is already in the Orbitree. Not adding it to the list" << std::endl;
2383  continue;
2384  }
2385  //std::cout << " Add orbit!" << std::endl;
2386  at(proto_clust[i].size()).push_back(GenericOrbit<ClustType>(proto_clust[i]));
2387  //std::cout << " get_equivalent()" << std::endl;
2388  at(proto_clust[i].size()).back().get_equivalent(sym_group, tol());
2389 
2390  bool include_subclusters;
2391  // check if should include_subclusters. default is true
2392  orbit_specs[i].get_else(include_subclusters, "include_subclusters", true);
2393  if(include_subclusters) {
2394  add_subclusters(at(proto_clust[i].size()).back().prototype, struc, verbose);
2395  }
2396 
2397  }
2398  sort();
2399  get_index();
2400  get_hierarchy();
2401  return true;
2402  }
2403 
2404  //********************************************************************
2406  template<typename ClustType>
2407  void GenericOrbitree<ClustType>::add_subclusters(const ClustType &big_clust, const Structure &prim, bool verbose) {
2408  if(verbose) std::cout << "In Orbitree::add_subclusters. Working on cluster: " << big_clust << std::endl;
2409  if(prim.factor_group().size() == 0) {
2410  std::cerr << "WARNING: In Orbitree::add_subclusters, prim's factor_group is empty. It must at least have one element (identity).\n";
2411  assert(0);
2412  }
2413 
2414  //Ensure that the lattices are the same:
2415  if(!(lattice == prim.lattice())) {
2416  std::cerr << "WARNING in Orbitree::add_subclusters, the lattice in prim and the lattice"
2417  << " that was used to construct this cluster are not the same" << std::endl;
2418  assert(0);
2419  }
2420 
2421  if(verbose) std::cout << "Size of this is : " << size() << std::endl;
2422  if(verbose) std::cout << "Size of cluster is : " << big_clust.size() << std::endl;
2423  if((size() - 1) < big_clust.size()) {
2424  std::cout << "Adding more Branches to this orbitree" << std::endl;
2425  for(Index temp = 0; temp <= (big_clust.size() - size()); temp++)
2426  (*this).push_back(GenericOrbitBranch<ClustType>(lattice));
2427  max_num_sites = big_clust.size();
2428  }
2429 
2430  Index i, j;
2431  std::string clean(80, ' ');
2432  Array<int> master_choose(big_clust.size(), 0);
2433  if(verbose) std::cout << "Master_Choose : " << master_choose << std::endl;
2434 
2435  for(i = 1; i <= big_clust.size(); i++) {
2436  if(verbose) std::cout << "Working on a subcluster of size: " << i << std::endl;
2437  Array<int> choose = master_choose;
2438  for(j = 0; j < i; j++)
2439  choose[choose.size() - j - 1] = 1;
2440  ClustType test_clust(prim.lattice());
2441  do {
2442  if(verbose) std::cout << "Choose is: " << choose << std::endl;
2443  test_clust.clear();
2444  for(j = 0; j < choose.size(); j++) {
2445  if(choose[j] == 1)
2446  test_clust.push_back(big_clust.at(j));
2447  }
2448  test_clust.within();
2449  test_clust.calc_properties();
2450 
2451  if(!contains(test_clust)) {
2452  if(verbose) std::cout << "Adding this cluster: " << test_clust << std::endl;
2453  at(i).push_back(GenericOrbit< ClustType >(test_clust));
2454  at(i).back().get_equivalent(prim.factor_group(), tol());
2455  }
2456  }
2457  while(choose.next_permute());
2458  }
2459  sort();
2460  get_index();
2461  get_hierarchy();
2462 
2463  }
2464 
2465  //********************************************************************
2466 
2468  template<typename ClustType>
2470  try {
2471 
2472  // Read the lattice first
2473 
2474  // Lattice lattice;
2475  CASM::from_json(lattice, json["lattice"]);
2476 
2477 
2478  //std::cout<<"Set the lattice"<<std::endl;
2479  // template<typename ClustType>
2480  // class GenericOrbitree : public Array< GenericOrbitBranch<ClustType> >
2481  //std::cout<<"Number of branches:"<<json["branches"].size()<<std::endl;
2482  resize(json["branches"].size());
2483  for(int i = 0; i < json["branches"].size(); i++) {
2484  //std::cout<<"Working on branch:"<<i<<std::endl;
2485  CASM::from_json(at(i), json["branches"][i]);
2486  }
2487 
2488  // int max_num_sites, min_num_components;
2489  CASM::from_json(max_num_sites, json["max_num_sites"]);
2490  CASM::from_json(min_num_components, json["min_num_components"]);
2491 
2492  // Array<double> max_length;
2493  CASM::from_json(max_length, json["max_length"]);
2494 
2495  // double min_length;
2496  CASM::from_json(min_length, json["min_length"]);
2497 
2498  // Array<int> num_clusts;
2499  CASM::from_json(num_clusts, json["num_clusts"]);
2500 
2501  // mutable Array<int> index_to_row, index_to_column;
2502  CASM::from_json(index_to_row, json["index_to_row"]);
2503  CASM::from_json(index_to_column, json["index_to_column"]);
2504 
2505  // mutable Array< Array<int> > index;
2506  CASM::from_json(index, json["index"]);
2507 
2508  // mutable int Norbits;
2509  CASM::from_json(Norbits, json["Norbits"]);
2510 
2511  // mutable Array< Array<int> > subcluster;
2512  CASM::from_json(subcluster, json["subcluster"]);
2513 
2514  std::cerr << "WARNING in GenericOrbitree<ClustType>::from_json "
2515  << "I HOPE YOU ARE NOT USING THIS AS A STAND ALONE RO"
2516  << "UTINE. Use it only as part of "
2517  << "GenericOrbitree<ClustType>::read_orbitree_from_json";
2518  }
2519  catch(...) {
2521  throw;
2522  }
2523  }
2524 
2525  //********************************************************************
2526 
2527  template<typename ClustType>
2529  m_b2asym.resize(struc.basis.size(), Array<Index>(2, -1));
2530  for(Index i = 0; i < struc.basis.size(); i++) {
2531  ClustType tclust(lattice);
2532 
2533  tclust.push_back(struc.basis[i]);
2534 
2535  tclust.within();
2536  tclust.calc_properties();
2537 
2538  if(!_asym_unit().contains(tclust, tol())) {
2539  m_asym_unit.push_back(GenericOrbit<ClustType>(tclust));
2540  m_asym_unit.back().get_equivalent(struc.factor_group(), tol());
2541  m_asym_unit.back().collect_basis_info(struc.basis);
2542  for(Index ne = 0; ne < m_asym_unit.back().size(); ne++) {
2543  m_b2asym[_asym_unit().back()[ne][0].basis_ind()][0] = _asym_unit().size() - 1;
2544  m_b2asym[_asym_unit().back()[ne][0].basis_ind()][1] = ne;
2545  m_asym_unit.back()[ne].set_nlist_inds(Array<Index>(1, _asym_unit().back()[ne][0].basis_ind()));
2546  }
2547  }
2548  }
2549  }
2550 
2551  //********************************************************************
2552 
2553  template<typename ClustType>
2555 
2556  if(bspecs()["basis_functions"]["site_basis_functions"].is_string()) {
2557  std::string func_type = bspecs()["basis_functions"]["site_basis_functions"].template get<std::string>();
2558 
2559  //std::cout << "Using " << func_type << " site basis functions." << std::endl << std::endl;
2560  switch(std::tolower(func_type[0])) {
2561  case 'c': { //chebychev
2562  for(Index i = 0; i < _asym_unit().size(); i++) {
2563  Array<double> tprob(m_asym_unit.prototype(i)[0].site_occupant().size(), 1.0 / double(_asym_unit().prototype(i)[0].site_occupant().size()));
2564  m_asym_unit.prototype(i).clust_basis.construct_orthonormal_discrete_functions(_asym_unit().prototype(i)[0].site_occupant(), tprob, _asym_unit().prototype(i)[0].basis_ind(), asym_unit().prototype(i).clust_group());
2565  for(Index ne = 0; ne < _asym_unit()[i].size(); ne++)
2566  m_asym_unit[i][ne].clust_basis.construct_orthonormal_discrete_functions(_asym_unit()[i][ne][0].site_occupant(), tprob, _asym_unit()[i][ne][0].basis_ind(), asym_unit().prototype(i).clust_group());
2567  }
2568  break;
2569  }
2570  case 'o': { //occupation
2571  for(Index i = 0; i < _asym_unit().size(); i++) {
2572  Array<double> tprob(_asym_unit().prototype(i)[0].site_occupant().size(), 0.0);
2573  if(tprob.size()) {
2574  tprob[0] = 1.0;
2575  m_asym_unit.prototype(i).clust_basis.construct_orthonormal_discrete_functions(_asym_unit().prototype(i)[0].site_occupant(), tprob, _asym_unit().prototype(i)[0].basis_ind(), asym_unit().prototype(i).clust_group());
2576  for(Index ne = 0; ne < _asym_unit()[i].size(); ne++)
2577  m_asym_unit[i][ne].clust_basis.construct_orthonormal_discrete_functions(_asym_unit()[i][ne][0].site_occupant(), tprob, _asym_unit()[i][ne][0].basis_ind(), asym_unit().prototype(i).clust_group());
2578  }
2579  }
2580  break;
2581  }
2582  default: {
2583  throw std::runtime_error(std::string("Parsing BSPECS.json, the specified 'site_basis_function' option -- \"") + func_type + "\" -- does not exist.\n"
2584  + "valid options are 'chebychev' or 'occupation'.\n");
2585  break;
2586  }
2587  }
2588  }
2589  else { // composition-optimized functions
2590  typedef std::map<std::string, double> SiteProb;
2591  std::vector<SiteProb> prob_vec(m_b2asym.size());
2592 
2593  auto it = bspecs()["basis_functions"].find("site_basis_functions");
2594  auto end_it = it;
2595  ++end_it;
2596 
2597  if(it->is_array()) {
2598  end_it = it->cend();
2599  it = it->cbegin();
2600  }
2601 
2602  bool sublat_spec = true;
2603  Index num_spec = 0;
2604  for(; it != end_it; ++it, num_spec++) {
2605  SiteProb tprob;
2606 
2607  auto it2 = (*it)["composition"].cbegin(), end_it2 = (*it)["composition"].cend();
2608  for(; it2 != end_it2; ++it2) {
2609  tprob[it2.name()] = it2->template get<double>();
2610  }
2611 
2612  if(!(it->contains("sublat_indices")) || !sublat_spec) {
2613  //we're using this block to check for errors *and* set 'sublat_spec'
2614  if(num_spec > 0) {
2615  throw std::runtime_error(std::string("Parse error: If multiple 'site_basis_functions' specifications are provided, 'sublat_indices' must be specified for each.\n")
2616  + " Example: \"site_basis_functions\" : [\n"
2617  + " {\n"
2618  + " \"sublat_indices\" : [0],\n"
2619  + " \"composition\" : [ \"SpeciesA\" : 0.2, \"SpeciesB\" : 0.8]\n"
2620  + " },\n"
2621  + " {\n"
2622  + " \"sublat_indices\" : [1,2],\n"
2623  + " \"composition\" : [ \"SpeciesA\" : 0.7, \"SpeciesB\" : 0.3]\n"
2624  + " }\n"
2625  + " ]\n");
2626  }
2627  else if(num_spec == 0)
2628  sublat_spec = false;
2629  }
2630 
2631  if(!sublat_spec) {
2632  for(auto &_vec : prob_vec)
2633  _vec = tprob;
2634  }
2635  else {
2636  it2 = (*it)["sublat_indices"].cbegin();
2637  end_it2 = (*it)["sublat_indices"].cend();
2638  for(; it2 != end_it2; ++it2) {
2639  Index b_ind = it2->template get<long>();
2640  if(!prob_vec[b_ind].empty())
2641  throw std::runtime_error("Duplicate sublat_indices specified in BSPECS.JSON\n");
2642 
2643  prob_vec[b_ind] = tprob;
2644  }
2645  }
2646  }
2647 
2648  for(Index i = 0; i < _asym_unit().size(); i++) {
2649  if(_asym_unit().prototype(i)[0].site_occupant().size() < 2)
2650  continue;
2651  Array<double> tprob(_asym_unit().prototype(i)[0].site_occupant().size(), 0.0);
2652  if(tprob.size() == 0)
2653  continue;
2654  Index b_ind = _asym_unit().prototype(i)[0].basis_ind();
2655  double tsum(0);
2656  for(Index ns = 0; ns < _asym_unit().prototype(i)[0].site_occupant().size(); ns++) {
2657  if(prob_vec[b_ind].find(_asym_unit().prototype(i)[0].site_occupant()[ns].name) == prob_vec[b_ind].end())
2658  throw std::runtime_error("In BSPECS.JSON, basis site " + std::to_string(b_ind) + " must have a composition specified for species " + _asym_unit().prototype(i)[0].site_occupant()[ns].name + "\n");
2659 
2660  tprob[ns] = prob_vec[b_ind][_asym_unit().prototype(i)[0].site_occupant()[ns].name];
2661  tsum += tprob[ns];
2662  }
2663  for(Index j = 0; j < tprob.size(); j++)
2664  tprob[j] /= tsum;
2665  m_asym_unit.prototype(i).clust_basis.construct_orthonormal_discrete_functions(_asym_unit().prototype(i)[0].site_occupant(), tprob, _asym_unit().prototype(i)[0].basis_ind(), asym_unit().prototype(i).clust_group());
2666  for(Index ne = 0; ne < _asym_unit()[i].size(); ne++)
2667  m_asym_unit[i][ne].clust_basis.construct_orthonormal_discrete_functions(_asym_unit()[i][ne][0].site_occupant(), tprob, _asym_unit()[i][ne][0].basis_ind(), asym_unit().prototype(i).clust_group());
2668  }
2669 
2670  //std::cout << "Using concentration-optimized site basis functions." << std::endl << std::endl;
2671  }
2672  }
2673 
2674 };
void print_eci_in(std::ostream &out) const
Array< Array< int > > index
Definition: Orbitree.hh:63
Eigen::MatrixXd MatrixXd
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
ClustType prototype
Definition: Orbit.hh:47
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:41
Array< Array< int > > subcluster
Definition: Orbitree.hh:68
void generate_decorated_orbitree(const GenericOrbitree< ClustType > &in_tree, const SymGroup &symgroup, PERIODICITY_TYPE ptype, bool full_decor=false)
void apply_sym(const SymOp &op)
void from_json(ClexDescription &desc, const jsonParser &json)
void generate_in_cell(const Structure &prim, const Lattice &cell, int num_images=0)
void write_proto_clust(std::string file) const
A Counter allows looping over many incrementing variables in one loop.
Definition: Counter.hh:71
Array< int > index_to_row
Definition: Orbitree.hh:62
void set_lattice(const Lattice &new_lat, COORD_TYPE mode)
sets lattice=new_lat and also updates all OrbitBranches, Orbits, and Clusters
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
Structure specifies the lattice and atomic basis of a crystal.
Definition: Structure.hh:29
void generate_orbitree_neighbour(const Structure &prim, const Array< int > maxNeighbour)
Unit Cell Coordinates.
void read_CSPECS(std::istream &stream)
Index find_index(Iterator begin, Iterator end, const T &value)
Equivalent to std::distance(begin, std::find(begin, end, value))
Definition: algorithm.hh:16
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
ReturnArray< Array< int > > get_full_decor_map() const
Definition: SiteCluster.cc:205
void generate_hop_orbitree(const GenericOrbitree< SiteCluster > &in_tree, const Structure &prim)
bool next_permute()
Definition: Array.hh:956
Main CASM namespace.
Definition: complete.cpp:8
GenericOrbitree< ClustType > & operator=(const GenericOrbitree< ClustType > &RHS)
std::string to_string(ENUM val)
Return string representation of enum class.
Definition: EnumIO.hh:83
const Lattice & lattice() const
void write_full_clust(std::string file) const
Index find(const ClustType &test_clust) const
If cluster/orbit exists in current orbitree, return its linear index; else, return number of orbits i...
void push_back(const GenericOrbit< ClustType > &new_orbit)
void generate_local_orbitree(const Structure &prim, const PhenomType &tmp_phenom_clust, bool include_phenom_clust_sites)
Constructs a local orbitree about a Phenom Cluster, given a Structure.
T get(Args...args) const
Get data from json, using one of several alternatives.
Definition: jsonParser.hh:729
void get_index() const
Populates 'index', 'index_to_row' and 'index_to_column' Arrays.
void print_proto_clust_funcs(std::ostream &out) const
Array< Array< Index > > m_b2asym
Definition: Orbitree.hh:243
Index basis_set_size() const
Count number of basis functions at each orbit and sum result.
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
double tol
jsonParser m_bspecs
Definition: Orbitree.hh:246
void clear()
Definition: Array.hh:216
bool read_custom_clusters_from_json(const jsonParser &json, const Structure &struc, const SymGroup &sym_group, bool verbose=false)
Add more orbits to Orbitree based on JSON input.
void print_proto_clust(std::ostream &out) const
const GenericOrbitBranch< ClustType > & _asym_unit() const
Definition: Orbitree.hh:234
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
const MasterSymGroup & factor_group() const
Definition: Structure.cc:94
void resize(Index NP)
Initialize NP orbitbranches in the Orbitree. Any existing orbits get deleted.
void write_full_decorated_clust(std::string file) const
Represents cartesian and fractional coordinates.
Definition: Coordinate.hh:34
typename multivector_impl::multivector_tmp< T, N >::type X
Definition: multivector.hh:28
void collect_basis_info(const Structure &struc)
void decorate(const Array< int > decor)
Definition: SiteCluster.hh:75
EigenIndex Index
For long integer indexing:
GenericOrbitBranch< ClustType > m_asym_unit
Definition: Orbitree.hh:239
void print_full_basis_info(std::ostream &out) const
Index size() const
Definition: PrimGrid.hh:108
GenericOrbitree(const Lattice &t_lat, double _tol)
Definition: Orbitree.hh:77
Array< CoordType > basis
Lattice vectors that specifies periodicity of the crystal.
bool get_else(T &t, const std::string &key, const T &default_value, Args...args) const
Definition: jsonParser.hh:749
Array< int > num_clusts
we don't use num_clusts yet. It might be a better way to specify how many clusters to enumerate ...
Definition: Orbitree.hh:56
void print_proto_decorated_clust(std::ostream &out) const
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 write_eci_in(std::string filename) const
T max(const T &A, const T &B)
Definition: CASM_math.hh:32
T min(const T &A, const T &B)
Definition: CASM_math.hh:25
Array< int > index_to_column
Definition: Orbitree.hh:62
double tol() const
Access orbitree tolerance.
void generate_orbitree_from_proto_file(std::string filename, const SymGroup &sym_group, PERIODICITY_TYPE ptype)
void print_full_clust(std::ostream &out) const
void _generate_asym_unit(const Structure &prim)
Array & append(const Array &new_tail)
Definition: Array.hh:897
static std::string NAME()
get a string with the name of the active mode
void sort()
Calls 'sort()' on each OrbitBranch to sort Orbits by lengthscale.
void generate_orbitree(const Structure &prim, bool verbose=false)
const ClustType & prototype(Index np, Index no) const
Access prototype of orbit (np, no)
CoordType get_site(const UnitCellCoord &ucc) const
const ClustType & equiv(Index np, Index no, Index ne) const
Access equivalent cluster 'ne' of orbit (np, no)
void read_orbitree_from_json(const std::string &json_file_name, const SymGroup &sym_group, const Structure &ref_struc)
void from_json(const jsonParser &json)
Assumes the pivot lattice is already set.
Coordinate_impl::FracCoordinate frac()
Set the fractional coordinate vector.
Definition: Coordinate.hh:581
Array< double > max_length
Definition: Orbitree.hh:51
void write_proto_decorated_clust(std::string file) const
GenericOrbit< ClustType > & orbit(Index np, Index no)
Access orbits using 2-D indexing.
void print_full_decorated_clust(std::ostream &out) const
Coordinate coord(Index l, CELL_TYPE lat_mode) const
Definition: PrimGrid.cc:223
void get_hierarchy() const
void generate_clust_bases(std::vector< BasisSet const * > const &global_args, Index max_poly_order=-1)
get clust_basis for all equivalent clusters
T & back()
Definition: Array.hh:177
bool contains(const Container &container, const T &value)
Equivalent to container.end() != std::find(container.begin(), container.end(), value) ...
Definition: algorithm.hh:66
bool contains(const ClustType &test_clust)
If cluster exists in current orbitree, return true.
Basic std::vector like container (deprecated)
void print(std::ostream &stream) const
void add_subclusters(const ClustType &big_clust, const Structure &prim, bool verbose=false)
Adding in subclusters of a specific cluster into *this Orbitree.
Index size(Index np) const
Number of orbits in OrbitBranch 'np'.
const jsonParser & bspecs() const
Definition: Orbitree.hh:104
static COORD_TYPE CHECK()
get the current mode (call using COORD_MODE::CHECK())