CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
PrimClex.cc
Go to the documentation of this file.
1 #include "casm/clex/PrimClex.hh"
2 
3 #include "casm/external/boost.hh"
4 
5 #include "casm/misc/algorithm.hh"
8 #include "casm/clex/ScelEnum.hh"
13 #include "casm/app/AppIO.hh"
15 
16 namespace CASM {
17  //*******************************************************************************************
18  // **** Constructors ****
19  //*******************************************************************************************
21  PrimClex::PrimClex(const Structure &_prim, const Logging &logging) :
22  Logging(logging),
23  prim(_prim) {
24 
26 
27  _init();
28 
29  return;
30  }
31 
32 
33  //*******************************************************************************************
36  PrimClex::PrimClex(const fs::path &_root, const Logging &logging):
37  Logging(logging),
38  root(_root),
39  m_dir(_root),
40  m_settings(_root),
41  prim(read_prim(m_dir.prim())) {
42 
43  _init();
44 
45  }
46 
49  void PrimClex::_init() {
50 
51  log().construct("CASM Project");
52  if(!root.empty()) {
53  log() << "from: " << root << "\n" << std::endl;
54  }
55 
56  std::vector<std::string> struc_mol_name = prim.get_struc_molecule_name();
57 
58  m_vacancy_allowed = false;
59  for(int i = 0; i < struc_mol_name.size(); ++i) {
60  if(is_vacancy(struc_mol_name[i])) {
61  m_vacancy_allowed = true;
62  m_vacancy_index = i;
63  }
64  }
65 
66  if(root.empty()) {
67  return;
68  }
69 
70  bool read_settings = false;
71  bool read_composition = true;
72  bool read_chem_ref = true;
73  bool read_configs = true;
74  bool clear_clex = false;
75 
76  refresh(read_settings, read_composition, read_chem_ref, read_configs, clear_clex);
77  }
78 
90  void PrimClex::refresh(bool read_settings,
91  bool read_composition,
92  bool read_chem_ref,
93  bool read_configs,
94  bool clear_clex) {
95 
96  log().custom("Load project data");
97 
98  if(read_settings) {
99  try {
100  m_settings = ProjectSettings(root, *this);
101  }
102  catch(std::exception &e) {
103  err_log().error("reading project_settings.json");
104  err_log() << "file: " << m_dir.project_settings() << "\n" << std::endl;
105  }
106  }
107 
108  if(read_composition) {
109  m_has_composition_axes = false;
110  auto comp_axes = m_dir.composition_axes();
111 
112  try {
113  if(fs::is_regular_file(comp_axes)) {
114  log() << "read: " << comp_axes << "\n";
115 
116  CompositionAxes opt(comp_axes);
117 
118  if(opt.has_current_axes) {
119  m_has_composition_axes = true;
120  m_comp_converter = opt.curr;
121  }
122  }
123  }
124  catch(std::exception &e) {
125  err_log().error("reading composition_axes.json");
126  err_log() << "file: " << comp_axes << "\n" << std::endl;
127  }
128  }
129 
130  if(read_chem_ref) {
131 
132  // read chemical reference
133  m_chem_ref.reset();
135 
136  try {
137  if(fs::is_regular_file(chem_ref_path)) {
138  log() << "read: " << chem_ref_path << "\n";
139  m_chem_ref = notstd::make_cloneable<ChemicalReference>(read_chemical_reference(chem_ref_path, prim, lin_alg_tol()));
140  }
141  }
142  catch(std::exception &e) {
143  err_log().error("reading chemical_reference.json");
144  err_log() << "file: " << chem_ref_path << "\n" << std::endl;
145  }
146  }
147 
148  if(read_configs) {
149 
150  supercell_list.clear();
151 
152  try {
153  // read supercells
154  if(fs::is_regular_file(m_dir.SCEL())) {
155  log() << "read: " << m_dir.SCEL() << "\n";
156  fs::ifstream scel(m_dir.SCEL());
157  read_supercells(scel);
158  }
159  }
160  catch(std::exception &e) {
161  err_log().error("reading SCEL");
162  err_log() << "file: " << m_dir.SCEL() << "\n" << std::endl;
163  }
164 
165  try {
166  // read config_list
167  if(fs::is_regular_file(get_config_list_path())) {
168  log() << "read: " << get_config_list_path() << "\n";
170  }
171  }
172  catch(std::exception &e) {
173  err_log().error("reading config_list.json");
174  err_log() << "file: " << m_dir.config_list() << "\n" << std::endl;
175  }
176  }
177 
178  if(clear_clex) {
179  m_nlist.reset();
180  m_orbitree.clear();
181  m_clexulator.clear();
182  m_eci.clear();
183  log() << "refresh cluster expansions\n";
184  }
185 
186  log() << std::endl;
187  }
188 
189  //*******************************************************************************************
190  // **** Accessors ****
191  //*******************************************************************************************
192 
194  std::string PrimClex::name() const {
195  return settings().name();
196  }
197 
198  //*******************************************************************************************
199  // ** Directory path accessors **
200  //*******************************************************************************************
203  return root;
204  }
205 
206  //*******************************************************************************************
208  fs::path PrimClex::get_path(const Index &scel_index) const {
209  return root / "training_data" / supercell_list[scel_index].get_name();
210  }
211 
212  //*******************************************************************************************
214  fs::path PrimClex::get_path(const Index &scel_index, const Index &config_index) const {
215  return get_path(scel_index) / supercell_list[scel_index].get_config(config_index).get_id();
216  }
217 
218  //*******************************************************************************************
221  return root / ".casm" / "config_list.json";
222  }
223 
224 
225  // ** Current settings accessors **
226 
227  // ** Composition accessors **
228 
229  //*******************************************************************************************
232  return m_has_composition_axes;
233  }
234 
235  //*******************************************************************************************
238  return m_comp_converter;
239  }
240 
241  // ** Chemical reference **
242 
243  //*******************************************************************************************
246  return static_cast<bool>(m_chem_ref);
247  }
248 
249  //*******************************************************************************************
252  return *m_chem_ref;
253  }
254 
255 
256  // ** Prim and Orbitree accessors **
257 
258  //*******************************************************************************************
260  const Structure &PrimClex::get_prim() const {
261  return prim;
262  }
263 
264  //*******************************************************************************************
265 
267 
268  // lazy neighbor list generation
269  if(!m_nlist) {
270 
271  // construct nlist
272  m_nlist = notstd::make_cloneable<PrimNeighborList>(
274  settings().nlist_sublat_indices().begin(),
276  );
277  }
278 
279  return *m_nlist;
280  }
281 
282  //*******************************************************************************************
285  return m_vacancy_allowed;
286  }
287 
288  //*******************************************************************************************
291  return m_vacancy_index;
292  }
293 
294 
295  // ** Supercell and Configuration accessors **
296 
297  //*******************************************************************************************
299  boost::container::stable_vector<Supercell> &PrimClex::get_supercell_list() {
300  return supercell_list;
301  };
302 
303  //*******************************************************************************************
305  const boost::container::stable_vector<Supercell> &PrimClex::get_supercell_list() const {
306  return supercell_list;
307  };
308 
309  //*******************************************************************************************
312  return supercell_list[i];
313  };
314 
315  //*******************************************************************************************
318  return supercell_list[i];
319  };
320 
321  //*******************************************************************************************
323  const Supercell &PrimClex::get_supercell(std::string scellname) const {
324  Index index;
325  if(!contains_supercell(scellname, index)) {
326  err_log().error("Accessing supercell");
327  err_log() << "supercell '" << scellname << "' not found." << std::endl;
328  throw std::invalid_argument("Error in PrimClex::get_supercell(std::string scellname) const: Not found");
329  }
330  return supercell_list[index];
331  };
332 
333  //*******************************************************************************************
335  Supercell &PrimClex::get_supercell(std::string scellname) {
336  return const_cast<Supercell &>(static_cast<const PrimClex &>(*this).get_supercell(scellname));
337  }
338 
339  //*******************************************************************************************
342  return get_supercell(add_supercell(lat));
343  }
344 
345  //*******************************************************************************************
347  const Configuration &PrimClex::configuration(const std::string &configname) const {
348  auto res = Configuration::split_name(configname);
349 
350  try {
351  return get_supercell(res.first).get_config_list().at(res.second);
352  }
353  catch(std::out_of_range &e) {
354  err_log().error("Invalid config index");
355  err_log() << "ERROR: In PrimClex::configuration(), configuration index out of range\n";
356  err_log() << "configname: " << configname << "\n";
357  err_log() << "index: " << res.second << "\n";
358  err_log() << "config_list.size(): " << get_supercell(res.first).get_config_list().size() << "\n";
359  throw e;
360  }
361  }
362 
363  //*******************************************************************************************
364 
366  return const_cast<Configuration &>(static_cast<const PrimClex &>(*this).configuration(configname));
367  }
368 
369  //*******************************************************************************************
372  if(supercell_list.size() == 0 || supercell_list[0].get_config_list().size() > 0)
373  return config_iterator(this, 0, 0);
374  return ++config_iterator(this, 0, 0);
375  }
376 
377  //*******************************************************************************************
380  return config_iterator(this, supercell_list.size(), 0);
381  }
382 
383  //*******************************************************************************************
386  if(supercell_list.size() == 0 || supercell_list[0].get_config_list().size() > 0)
387  return config_const_iterator(this, 0, 0);
388  return ++config_const_iterator(this, 0, 0);
389  }
390 
391  //*******************************************************************************************
394  return config_const_iterator(this, supercell_list.size(), 0);
395  }
396 
397  //*******************************************************************************************
400  if(supercell_list.size() == 0 || supercell_list[0].get_config_list().size() > 0)
401  return config_const_iterator(this, 0, 0);
402  return ++config_const_iterator(this, 0, 0);
403  }
404 
405  //*******************************************************************************************
408  return config_const_iterator(this, supercell_list.size(), 0);
409  }
410 
411  //*******************************************************************************************
414  //std::cout << "BEGINNING SELECTED CONFIG ITERATOR\n"
415  // << "supercell_list.size() is " << supercell_list.size() << "\n";
416 
417  if(supercell_list.size() == 0 || (supercell_list[0].get_config_list().size() > 0 && supercell_list[0].get_config(0).selected()))
418  return config_iterator(this, 0, 0, true);
419  return ++config_iterator(this, 0, 0, true);
420  }
421 
422  //*******************************************************************************************
425  return config_iterator(this, supercell_list.size(), 0, true);
426  }
427 
428  //*******************************************************************************************
431  if(supercell_list.size() == 0 || (supercell_list[0].get_config_list().size() > 0 && supercell_list[0].get_config(0).selected()))
432  return config_const_iterator(this, 0, 0, true);
433  return ++config_const_iterator(this, 0, 0, true);
434  }
435 
436  //*******************************************************************************************
439  return config_const_iterator(this, supercell_list.size(), 0, true);
440  }
441 
442 
443  //*******************************************************************************************
444  // **** IO ****
445  //*******************************************************************************************
450  void PrimClex::write_config_list(std::set<std::string> scel_to_delete) {
451 
452  if(supercell_list.size() == 0) {
453  fs::remove(get_config_list_path());
454  return;
455  }
456 
457  jsonParser json;
458 
459  if(fs::exists(get_config_list_path())) {
460  json.read(get_config_list_path());
461  }
462  else {
463  json.put_obj();
464  }
465 
466  for(Index s = 0; s < supercell_list.size(); s++) {
467  if(scel_to_delete.count(supercell_list[s].get_name())) {
468  json["supercells"].erase(supercell_list[s].get_name());
469  }
470  else {
471  supercell_list[s].write_config_list(json);
472  }
473  }
474 
475  SafeOfstream file;
476  file.open(get_config_list_path());
477  json.print(file.ofstream());
478  file.close();
479 
480  return;
481  }
482 
483  // **** Operators ****
484 
485 
486  // **** Unorganized mess of functions ... ****
487 
493  ScelEnumByProps e(*this, enum_props);
494  for(auto it = e.begin(); it != e.end(); ++it) {}
495  return;
496  }
497 
498  //*******************************************************************************************
510  //*******************************************************************************************
512  if(!superlat.is_supercell_of(prim.lattice())) {
513  std::cerr << "ERROR in PrimClex::add_canonical_supercell()." << std::endl
514  << " Passed a Supercell Lattice that is not a superlattice of PRIM lattice\n" << std::endl;
515  assert(0);
516  exit(1);
517  }
518 
519  // temporary version, just check transf_mat equivalence
520  // Does this check for equivalent supercells with different transformation matrices? Seems like it should
521  // Insert second loop that goes over a symmetry operation list and applies it to the transformation matrix
522  Supercell scel(this, superlat);
523  scel.set_id(supercell_list.size());
524  for(Index i = 0; i < supercell_list.size(); i++) {
525  if(supercell_list[i].get_transf_mat() == scel.get_transf_mat())
526  return i;
527  }
528 
529  // if not already existing, add it
530  supercell_list.push_back(scel);
531  return supercell_list.size() - 1;
532  }
533  //*******************************************************************************************
549  //*******************************************************************************************
551 
553 
554  }
555 
556  //*******************************************************************************************
557  void PrimClex::print_supercells(std::set<std::string> scel_to_delete) const {
558 
559 
560  // also write supercells/supercell_path directories with LAT files
561  try {
562  fs::create_directory(get_path() / "training_data");
563  }
564  catch(const fs::filesystem_error &ex) {
565  std::cerr << "Error in PrimClex::print_supercells()." << std::endl;
566  std::cerr << ex.what() << std::endl;
567  }
568 
569  fs::ofstream scelfile(get_path() / "training_data" / "SCEL");
570 
571  print_supercells(scelfile, scel_to_delete);
572 
573  for(Index i = 0; i < supercell_list.size(); i++) {
574  try {
575  if(!scel_to_delete.count(supercell_list[i].get_name())) {
576  fs::create_directory(supercell_list[i].get_path());
577 
578  fs::path latpath = supercell_list[i].get_path() / "LAT";
579  if(!fs::exists(latpath)) {
580  fs::ofstream latfile(latpath);
581  supercell_list[i].get_real_super_lattice().print(latfile);
582  }
583  }
584  }
585  catch(const fs::filesystem_error &ex) {
586  std::cerr << "Error in PrimClex::print_supercells()." << std::endl;
587  std::cerr << ex.what() << std::endl;
588  }
589  }
590  }
591 
592  //*******************************************************************************************
593  void PrimClex::print_supercells(std::ostream &stream, std::set<std::string> scel_to_delete) const {
594  for(Index i = 0; i < supercell_list.size(); i++) {
595  if(!scel_to_delete.count(supercell_list[i].get_name())) {
596  stream << "Supercell Name: '" << supercell_list[i].get_name() << "' Number: " << i << " Volume: " << supercell_list[i].get_transf_mat().determinant() << "\n";
597  stream << "Supercell Transformation Matrix: \n";
598  stream << supercell_list[i].get_transf_mat();
599  stream << "\n";
600  }
601  }
602  }
603 
604  //*******************************************************************************************
605  void PrimClex::read_supercells(std::istream &stream) {
606  // expect a file with format:
607  //
608  // Supercell Number: 0 Volume: 1
609  // Supercell Transformation Matrix:
610  // 1 0 0
611  // 0 1 0
612  // 0 0 1
613  //
614  // Supercell Number: 1 Volume: 2
615  // Supercell Transformation Matrix:
616  // 1 0 -1
617  // 0 1 0
618  // 0 0 2
619 
620  Eigen::Matrix3d mat;
621 
622  // check for non-canonical
623  std::vector<std::pair<Lattice, Lattice> > non_canon;
624 
625  // read && sort
626  std::set<Supercell> in_scel;
627 
628  std::string s;
629  while(!stream.eof()) {
630  std::getline(stream, s);
631  if(s[0] == 'S') {
632  std::getline(stream, s);
633  stream >> mat;
634 
635  Lattice lat(prim.lattice().lat_column_mat()*mat);
636  in_scel.emplace(this, lat);
637 
639  lat,
640  get_prim().point_group(),
642 
643  if(!almost_equal(canon.lat_column_mat(), lat.lat_column_mat(), crystallography_tol())) {
644  non_canon.push_back(std::make_pair(lat, canon));
645  }
646  }
647  }
648 
649  // insert sorted
650  for(const auto &scel : in_scel) {
651  add_canonical_supercell(scel.get_real_super_lattice());
652  }
653 
654  if(non_canon.size()) {
655  log() << std::endl;
656 
657  log().warning("Non-canonical supercells");
658  log() << "A bug in a previous version of CASM resulted in the generation \n"
659  "of the following non-canonical supercells: \n";
660  for(const auto &val : non_canon) {
661  log() << " existing name: " << generate_name(calc_transf_mat(val.first))
662  << " canonical name: " << generate_name(calc_transf_mat(val.second)) << "\n";
663  }
664  log() << std::endl;
665  log() << "To prevent errors, please use 'casm import' to convert existing \n"
666  "configurations and data.\n";
667  log() << std::endl;
668 
669  }
670  }
671 
672  //*******************************************************************************************
679  //*******************************************************************************************
681 
683 
684  if(!json.contains("supercells")) {
685  return;
686  }
687 
688  for(Index i = 0; i < supercell_list.size(); i++) {
689  supercell_list[i].read_config_list(json);
690  }
691  }
692 
693  //*******************************************************************************************
694  /*
695  * Run through all the supercells and add up how many configurations are selected
696  * in each one of them.
697  */
698  //*******************************************************************************************
699 
701  int amount_selected = 0;
702  for(Index s = 0; s < supercell_list.size(); s++) {
703  amount_selected += supercell_list[s].amount_selected();
704  }
705  return amount_selected;
706  }
707 
708  //*******************************************************************************************
709  bool PrimClex::contains_supercell(std::string scellname, Index &index) const {
710  for(Index i = 0; i < supercell_list.size(); i++) {
711  if(supercell_list[i].get_name() == scellname) {
712  index = i;
713  return true;
714  }
715  }
716  index = supercell_list.size();
717  return false;
718 
719  };
720 
721  bool PrimClex::contains_supercell(const Supercell &scel) const {
722  Index tmp;
723  return contains_supercell(scel, tmp);
724  }
725 
726  bool PrimClex::contains_supercell(const Supercell &scel, Index &index) const {
727  return contains_supercell(scel.get_name(), index);
728  }
729 
730  //*******************************************************************************************
731  Eigen::Matrix3i PrimClex::calc_transf_mat(const Lattice &superlat) const {
733  if(!is_integer(ttrans, TOL)) {
734  std::cerr << "Error in PrimClex::calc_transf_mat(const Lattice &superlat)" << std::endl
735  << " Bad supercell, the transformation matrix is not integer. Exiting!" << std::endl;
736  exit(1);
737  }
738  return iround(ttrans);
739  }
740 
741  //*******************************************************************************************
742 
750 
751  m_comp_converter = _converter;
752  m_has_composition_axes = true;
753 
754  }
755 
756  //*******************************************************************************************
757  /*
760  void PrimClex::clear_reference_states() {
761  for(int i = 0; i < composition_axes().independent_compositions() + 1; i++) {
762  fs::remove(dir().ref_state(settings().calctype(), settings().ref(), i));
763  }
764  generate_references();
765  }
766  */
767  //*******************************************************************************************
768  /*
771  void PrimClex::set_reference_state(int refid, const Configuration &config) {
772 
773  //std::cout << "begin set_reference_state()" << std::endl;
774 
775  std::string reason_invalid;
776  if(!valid_reference_state(refid, config, reason_invalid)) {
777  std::cerr << "Error in PrimClex::set_reference_state." << std::endl
778  << " Could not use SCEL: " << config.get_supercell().get_name() << " ConfigID: " << config.get_id() << " for reference state: " << refid << std::endl
779  << " " << reason_invalid << std::endl;
780  exit(1);
781  }
782 
783  jsonParser json;
784 
785  json["supercell_name"] = config.get_supercell().get_name();
786  json["configid"] = config.get_id();
787 
788  json["param_composition"] = config.get_param_composition();
789  json["ref_state"] = config.calc_properties();
790 
791  //std::cout << "Set refid: " << refid << std::endl;
792  //std::cout << "Reference State:\n" << json << "\n" << std::endl;
793 
794  json.write(dir().ref_state(settings().calctype(), settings().ref(), refid));
795 
796  //std::cout << "finish set_reference_state()" << std::endl;
797  }
798  */
799  //*******************************************************************************************
800  /*
806  bool PrimClex::valid_reference_state(int refid, const Configuration &config, std::string &reason_invalid) const {
807 
808  // Check that the Configuration has all the curr_property calculated
809  for(Index i = 0; i < get_curr_property().size(); i++) {
810  if(!config.calc_properties().contains(get_curr_property()[i])) {
811  reason_invalid = "You are attempting to use a Configuration for which the property '" + get_curr_property()[i] + "' has not been calculated.";
812  return false;
813  }
814  }
815 
816  // Check that a Configuration is not being used for multiple reference states
817  for(int i = 0; i < composition_axes().independent_compositions() + 1; i++) {
818  if(i == refid)
819  continue;
820 
821  if(!fs::exists(dir().ref_state(settings().calctype(), settings().ref(), i)))
822  continue;
823 
824  jsonParser json(dir().ref_state(settings().calctype(), settings().ref(), i));
825 
826  if(json["configid"] == "custom" || json["supercell_name"] == "custom")
827  continue;
828 
829  if(json["configid"] == config.get_id() && json["supercell_name"] == config.get_supercell().get_name()) {
830  reason_invalid = "You are attempting to use the same Configuration for >1 reference state and I can't allow that.";
831  return false;
832  }
833  }
834 
835  // Here I should check that references span the necessary composition space, but I'm not yet
836 
837  // First read all reference states that have already been set, then check that this new one is not a linear combination of those
838 
839  return true;
840  }
841  */
842  //*******************************************************************************************
843  /*
848  void PrimClex::set_reference_state_auto() {
849 
850  //std::cout << "begin set_reference_state_auto()" << std::endl;
851 
854 
855  // Clear current references
856  clear_reference_states();
857 
858  int Naxes = composition_axes().independent_compositions();
859 
860  //std::cout << "Naxes: " << Naxes << std::endl;
861 
862  Eigen::VectorXd target = Eigen::VectorXd::Zero(Naxes);
863 
864  //std::cout << "Ref: " << 0 << " target: " << target.transpose() << std::endl;
865  set_reference_state(0, closest_calculated_config(target));
866 
867  for(int i = 0; i < Naxes; i++) {
868 
869  target(i) = 1.0;
870  //std::cout << "Ref: " << i + 1 << " target: " << target.transpose() << std::endl;
871  set_reference_state(i + 1, closest_calculated_config(target));
872  target(i) = 0.0;
873  }
874 
875  //std::cout << "generate references" << std::endl;
876  generate_references();
877 
878  //std::cout << "finish set_reference_state_auto()" << std::endl;
879 
880  }
881  */
882 
883  //*******************************************************************************************
884  /*
891  void PrimClex::generate_references() {
892 
893  //std::cout << "begin PrimClex::generate_references()" << std::endl;
894 
895  for(config_iterator it = config_begin(); it != config_end(); ++it) {
896  it->generate_reference();
897  }
898 
899  write_config_list();
900 
901  //std::cout << "finish PrimClex::generate_references()" << std::endl;
902 
903  }
904  */
905 
906  //*******************************************************************************************
908 
909  //*******************************************************************************************
910  /*
913  const Configuration &PrimClex::closest_calculated_config(const Eigen::VectorXd &target_param_comp) const {
914 
915  //std::cout << "begin closest_calculated_config()" << std::endl;
916 
921 
922  Eigen::VectorXd param_comp;
923  Eigen::VectorXd closest_comp;
924 
925  double curr_dist;
926  double close_dist = -1;
927  Index close_super = -1;
928  Index close_config;
929  Index close_size;
930 
931  for(Index i = 0; i < supercell_list.size(); i++) {
932  for(Index j = 0; j < supercell_list[i].get_config_list().size(); j++) {
933 
934  const Configuration &config = supercell_list[i].get_config(j);
935 
936  // check if the config has been calculated
937  //std::cout << "\n\nScell: " << supercell_list[i].get_name() << " Config: " << j << "\n" << config.calc_properties() << std::endl;
938 
939  if(config.calc_properties().size() == 0)
940  continue;
941 
942  curr_dist = (target_param_comp - config.get_param_composition()).norm();
943 
944  if(!valid_index(close_super) ||
945  (almost_equal(curr_dist, close_dist, TOL) && config.size() < close_size) ||
946  (curr_dist < close_dist)) {
947  close_super = i;
948  close_config = j;
949  close_dist = curr_dist;
950  close_size = config.size();
951  }
952 
953  } // for j
954  } // for i
955 
956  if(!valid_index(close_super)) {
957  std::cerr << "Error in PrimClex::closest_calculated_config" << std::endl
958  << " Could not find a calculated Configuration." << std::endl;
959  exit(1);
960  }
961 
962  //std::cout << "Closest Calculated: SCEL: " << supercell_list[close_super].get_name() << " Config: " <<
963  // close_config << " ParamComp: " << supercell_list[close_super].get_config(close_config).get_param_composition().transpose() << std::endl;
964 
965  //std::cout << "finish closest_calculated_config()" << std::endl;
966 
967  return supercell_list[close_super].get_config(close_config);
968  }
969  */
970 
971  //*******************************************************************************************
972 
974  Eigen::MatrixXd tau(prim.basis.size(), 3);
975  for(int i = 0; i < prim.basis.size(); i++) {
976  tau.row(i) = prim.basis[i].const_cart().transpose();
977  }
978  return tau;
979  }
980 
981  //*******************************************************************************************
983  bool PrimClex::has_orbitree(const ClexDescription &key) const {
984  auto it = m_orbitree.find(key);
985  if(it == m_orbitree.end()) {
986  if(!fs::exists(dir().clust(key.bset))) {
987  return false;
988  }
989  }
990  return true;
991 
992  };
993 
994  //*******************************************************************************************
995 
997 
998  auto it = m_orbitree.find(key);
999  if(it == m_orbitree.end()) {
1000  it = m_orbitree.insert(std::make_pair(key, SiteOrbitree(get_prim().lattice(), crystallography_tol()))).first;
1001  SiteOrbitree &tree = it->second;
1002 
1003  // these could be specified via settings
1004  tree.min_num_components = 2;
1005  tree.min_length = 0.0001;
1006 
1007  from_json(jsonHelper(tree, prim), jsonParser(dir().clust(key.bset)));
1008  tree.generate_clust_bases();
1009 
1010  }
1011 
1012  return it->second;
1013 
1014  }
1015 
1016  //*******************************************************************************************
1017 
1019  auto it = m_clexulator.find(key);
1020  if(it == m_clexulator.end()) {
1021  if(!fs::exists(dir().clexulator_src(settings().name(), key.bset))) {
1022  return false;
1023  }
1024  }
1025  return true;
1026  }
1027 
1028  //*******************************************************************************************
1029 
1031 
1032  auto it = m_clexulator.find(key);
1033  if(it == m_clexulator.end()) {
1034 
1035  if(!fs::exists(dir().clexulator_src(settings().name(), key.bset))) {
1036  throw std::runtime_error(
1037  std::string("Error loading clexulator ") + key.bset + ". No basis functions exist.");
1038  }
1039 
1040  try {
1041  it = m_clexulator.insert(
1042  std::make_pair(key, Clexulator(settings().name() + "_Clexulator",
1043  dir().clexulator_dir(key.bset),
1044  nlist(),
1045  log(),
1046  settings().compile_options(),
1047  settings().so_options()))).first;
1048  }
1049  catch(std::exception &e) {
1050  // not sure why this fails...
1051  // log() << "Error constructing Clexulator. Current settings: \n" << std::endl;
1052  // settings().print_compiler_settings_summary(log());
1053 
1054  std::cout << "Error constructing Clexulator. Current settings: \n" << std::endl;
1055  Log tlog(std::cout);
1057  throw;
1058  }
1059  }
1060  return it->second;
1061  }
1062 
1063  //*******************************************************************************************
1064 
1065  bool PrimClex::has_eci(const ClexDescription &key) const {
1066 
1067  auto it = m_eci.find(key);
1068  if(it == m_eci.end()) {
1069  return fs::exists(dir().eci(key.property, key.calctype, key.ref, key.bset, key.eci));
1070  }
1071  return true;
1072  }
1073 
1074  //*******************************************************************************************
1075 
1076  const ECIContainer &PrimClex::eci(const ClexDescription &key) const {
1077 
1078  auto it = m_eci.find(key);
1079  if(it == m_eci.end()) {
1080  fs::path eci_path = dir().eci(key.property, key.calctype, key.ref, key.bset, key.eci);
1081  if(!fs::exists(eci_path)) {
1082  throw std::runtime_error(
1083  std::string("Error loading ECI. eci.json does not exist.\n")
1084  + " Expected at: " + eci_path.string());
1085  }
1086 
1087  it = m_eci.insert(std::make_pair(key, read_eci(eci_path))).first;
1088  }
1089  return it->second;
1090  }
1091 
1092  //*******************************************************************************************
1097  SiteOrbitree make_orbitree(Structure &prim, const jsonParser &json, double _tol) {
1098 
1099  try {
1100 
1101  SiteOrbitree tree(prim.lattice(), _tol);
1102  tree.set_bspecs(json);
1103  // --- first generate global orbitree -------------
1104 
1105 
1106  //global_orbitree.read_CSPECS(in_clust);
1107  tree.min_num_components = 2;
1108  tree.min_length = -1.5 * _tol;
1109 
1110  tree.max_length.clear();
1111  auto update_max_length = [&](int branch, double max_length) {
1112  while(branch > tree.max_length.size() - 1) {
1113  tree.max_length.push_back(0.0);
1114  }
1115  tree.max_length[branch] = max_length;
1116  };
1117 
1118  for(auto it = json["orbit_branch_specs"].cbegin(); it != json["orbit_branch_specs"].cend(); ++it) {
1119  update_max_length(std::stoi(it.name()), it->find("max_length")->get<double>());
1120  }
1121  tree.max_num_sites = tree.max_length.size() - 1;
1122 
1123  tree.generate_orbitree(prim);
1124 
1125  // --- then add custom orbits --------------------
1126 
1127  if(json.contains("orbit_specs")) {
1128  bool verbose = false;
1129  tree.read_custom_clusters_from_json(json["orbit_specs"], prim, prim.factor_group(), verbose);
1130  }
1131  tree.collect_basis_info(prim);
1132 
1133  return tree;
1134  }
1135  catch(...) {
1136  std::cerr << "Error in make_orbitree, with JSON input: \n";
1137  std::cerr << json << "\n";
1138  throw;
1139  }
1140 
1141  }
1142 
1143  void set_nlist_ind(const Structure &prim, SiteOrbitree &tree, const PrimNeighborList &nlist, double xtal_tol) {
1144 
1145  //For each site we encounter we access the appropriate slot in the neighbor list and append all other sites
1146  //to it in the form of UnitCellCoords
1147 
1148  Array<Index> clust_nlist_inds;
1149 
1150  const auto &sublat_indices = nlist.sublat_indices();
1151 
1152  Index N_sublat = sublat_indices.size();
1153 
1154  //branches
1155  for(Index i = 0; i < tree.size(); i++) {
1156  //orbits
1157  for(Index j = 0; j < tree[i].size(); j++) {
1158  //clusters
1159  for(Index k = 0; k < tree[i][j].size(); k++) {
1160 
1161  clust_nlist_inds.resize(tree[i][j][k].size());
1162 
1163  //sites
1164  for(Index l = 0; l < tree[i][j][k].size(); l++) {
1165 
1166  //tuccl corresponds to a particular site we're looking at
1167  UnitCellCoord tuccl(tree[i][j][k][l], prim, xtal_tol);
1168 
1169  //neighbor sites
1170  for(Index b = 0; b < tree[i][j][k].size(); b++) {
1171 
1172  //tuccb corresponds to a site that neighbors tuccl
1173  UnitCellCoord tuccb(tree[i][j][k][b], prim, xtal_tol);
1174  UnitCell delta = tuccb.unitcell() - tuccl.unitcell();
1175 
1176  auto unitcell_index = find_index(nlist, delta);
1177  if(unitcell_index == nlist.size()) {
1178  std::cerr << "Error generating unitcell index." << std::endl;
1179  std::cerr << " Did not find unitcell: " << delta.transpose() << " in the prim nlist." << std::endl;
1180  exit(1);
1181  }
1182 
1183  auto sublat_index = find_index(sublat_indices, tuccb.sublat());
1184  if(sublat_index == sublat_indices.size()) {
1185  std::cerr << "Error generating sublat index" << std::endl;
1186  std::cerr << " Did not find sublat: " << tuccb.sublat() << " in the nlist sublattice indices: " << jsonParser(sublat_indices) << std::endl;
1187  exit(1);
1188  }
1189 
1190  clust_nlist_inds[b] = unitcell_index * N_sublat + sublat_index;
1191 
1192  // //If delta is not already in nlist, add it (the value of clust_nlist_inds[b] makes sense after the push_back)
1193  // if(clust_nlist_inds[b] == nlist.size()) {
1194  // nlist.push_back(delta);
1195  // }
1196  }
1197 
1198  // we set the first set of nlist_inds as the current indices
1199  if(l == 0) {
1200  tree[i][j][k].set_nlist_inds(clust_nlist_inds);
1201  }
1202 
1203  // save any other unique ones that we find
1204  Index t(0);
1205  for(t = 0; t < tree[i][j][k].trans_nlists().size(); t++) {
1206  if(clust_nlist_inds.all_in(tree[i][j][k].trans_nlist(t)))
1207  break;
1208  }
1209  if(t == tree[i][j][k].trans_nlists().size())
1210  tree[i][j][k].add_trans_nlist(clust_nlist_inds);
1211  }
1212  }
1213  }
1214  }
1215  }
1216 
1217  //*******************************************************************************************
1219  void print_clexulator(const Structure &prim,
1220  SiteOrbitree &tree,
1221  const PrimNeighborList &nlist,
1222  std::string class_name,
1223  std::ostream &stream,
1224  double xtal_tol) {
1225 
1226  set_nlist_ind(prim, tree, nlist, xtal_tol);
1227 
1228  DoFManager dof_manager;
1229  Index Nsublat = prim.basis.size();
1230  for(Index b = 0; b < Nsublat; b++) {
1231  if(prim.basis[b].site_occupant().size() > 1) {
1232  dof_manager.add_dof(prim.basis[b].site_occupant().type_name());
1233  break;
1234  }
1235  }
1236  for(Index b = 0; b < Nsublat; b++) {
1237  for(Index i = 0; i < prim.basis[i].displacement().size(); i++)
1238  dof_manager.add_dof(prim.basis[b].displacement()[i].type_name());
1239  }
1240 
1241  dof_manager.resize_neighborhood(nlist.size()*nlist.sublat_indices().size());
1242 
1243  // We can add more as needed
1244  dof_manager.register_dofs(tree);
1245 
1246  Index N_corr(tree.basis_set_size());
1247  std::stringstream private_def_stream, public_def_stream, interface_imp_stream, bfunc_imp_stream;
1248 
1249  std::string uclass_name;
1250  for(Index i = 0; i < class_name.size(); i++)
1251  uclass_name.push_back(std::toupper(class_name[i]));
1252 
1253  std::string indent(2, ' ');
1254  private_def_stream <<
1255 
1256  indent << " /// \\brief Clone the Clexulator\n" <<
1257  indent << " virtual " << class_name << "* _clone() const override {\n" <<
1258  indent << " return new " << class_name << "(*this);\n" <<
1259  indent << " }\n\n" <<
1260 
1261  indent << " // typedef for method pointers\n" <<
1262  indent << " typedef double (" << class_name << "::*BasisFuncPtr)() const;\n\n" <<
1263 
1264  indent << " // typedef for method pointers\n" <<
1265  indent << " typedef double (" << class_name << "::*DeltaBasisFuncPtr)(int, int) const;\n\n" <<
1266 
1267  indent << " // array of pointers to member functions for calculating basis functions\n" <<
1268  indent << " BasisFuncPtr m_orbit_func_list[" << N_corr << "];\n\n" <<
1269 
1270  indent << " // array of pointers to member functions for calculating flower functions\n" <<
1271  indent << " BasisFuncPtr m_flower_func_lists[" << Nsublat << "][" << N_corr << "];\n\n" <<
1272 
1273  /**** for separate 1D method pointer lists:
1274  indent << " BasisFuncPtr
1275  for(Index i = 0; i < Nsublat; i++) {
1276  private_def_stream << " m_flower_func_at_" << i << "_list[" << N_corr << "]";
1277  if(i + 1 < Nsublat)
1278  private_def_stream << ',';
1279  }
1280  private_def_stream << ";\n\n" <<
1281  **/
1282 
1283  indent << " // array of pointers to member functions for calculating DELTA flower functions\n" <<
1284  indent << " DeltaBasisFuncPtr m_delta_func_lists[" << Nsublat << "][" << N_corr << "];\n\n";
1285 
1286  /**** for separate 1D method pointer lists:
1287  indent << " DeltaBasisFuncPtr";
1288 
1289  for(Index i = 0; i < Nsublat; i++) {
1290  private_def_stream << " m_delta_func_at_" << i << "_list[" << N_corr << "]";
1291  if(i + 1 < Nsublat)
1292  private_def_stream << ',';
1293  }
1294  private_def_stream << ";\n\n";
1295  **/
1296 
1297  dof_manager.print_clexulator_member_definitions(private_def_stream, tree, indent + " ");
1298 
1299  // perhaps some more correlation calculating options here
1300  dof_manager.print_clexulator_private_method_definitions(private_def_stream, tree, indent + " ");
1301 
1302  private_def_stream <<
1303  indent << " //default functions for basis function evaluation \n" <<
1304  indent << " double zero_func() const{ return 0.0;};\n" <<
1305  indent << " double zero_func(int,int) const{ return 0.0;};\n\n";
1306 
1307  public_def_stream <<
1308  indent << " " << class_name << "();\n\n" <<
1309  indent << " ~" << class_name << "();\n\n" <<
1310 
1311  indent << " /// \\brief Clone the " << class_name << "\n" <<
1312  indent << " std::unique_ptr<" << class_name << "> clone() const { \n" <<
1313  indent << " return std::unique_ptr<" << class_name << ">(_clone()); \n" <<
1314  indent << " }\n\n" <<
1315 
1316  indent << " /// \\brief Calculate contribution to global correlations from one unit cell\n" <<
1317  indent << " void calc_global_corr_contribution(double *corr_begin) const override;\n\n" <<
1318 
1319  indent << " /// \\brief Calculate contribution to select global correlations from one unit cell\n" <<
1320  indent << " void calc_restricted_global_corr_contribution(double *corr_begin, size_type const* ind_list_begin, size_type const* ind_list_end) const override;\n\n" <<
1321 
1322  indent << " /// \\brief Calculate point correlations about basis site 'b_index'\n" <<
1323  indent << " void calc_point_corr(int b_index, double *corr_begin) const override;\n\n" <<
1324 
1325  indent << " /// \\brief Calculate select point correlations about basis site 'b_index'\n" <<
1326  indent << " void calc_restricted_point_corr(int b_index, double *corr_begin, size_type const* ind_list_begin, size_type const* ind_list_end) const override;\n\n" <<
1327 
1328  indent << " /// \\brief Calculate the change in point correlations due to changing an occupant\n" <<
1329  indent << " void calc_delta_point_corr(int b_index, int occ_i, int occ_f, double *corr_begin) const override;\n\n" <<
1330 
1331  indent << " /// \\brief Calculate the change in select point correlations due to changing an occupant\n" <<
1332  indent << " void calc_restricted_delta_point_corr(int b_index, int occ_i, int occ_f, double *corr_begin, size_type const* ind_list_begin, size_type const* ind_list_end) const override;\n\n";
1333 
1334  dof_manager.print_clexulator_public_method_definitions(public_def_stream, tree, indent + " ");
1335 
1336 
1337  //linear function index
1338  Index lf = 0, tlf;
1339 
1340  Array<FunctionVisitor *> labelers(dof_manager.get_function_label_visitors());
1341  //std::cout << "Initialized " << labelers.size() << " labelers \n";
1342 
1343  Array<std::string> orbit_method_names(N_corr);
1344  Array<Array<std::string> > flower_method_names(Nsublat, Array<std::string>(N_corr));
1345  //Array< Array<Array<std::string> > > dflower_method_names(N_corr, Array<Array<std::string> >(Nsublat));
1346 
1347  //this is very configuration-centric
1348  Array<Array<std::string> > dflower_method_names(Nsublat, Array<std::string>(N_corr));
1349 
1350  // temporary storage for formula
1351  Array<std::string> formulae, tformulae;
1352 
1353  bool make_newline(false);
1354 
1355  //loop over orbits
1356  for(Index np = 0; np < tree.size(); np++) {
1357  for(Index no = 0; no < tree[np].size(); no++) {
1358  if(np == 0)
1359  bfunc_imp_stream <<
1360  indent << "// Basis functions for empty cluster:\n";
1361  else {
1362  bfunc_imp_stream <<
1363  indent << "/**** Basis functions for orbit " << np << ", " << no << "****\n";
1364  tree[np][no].prototype.print(bfunc_imp_stream, '\n');
1365  bfunc_imp_stream << "****/\n";
1366  }
1367 
1368  formulae = tree[np][no].orbit_function_cpp_strings(labelers);
1369  tlf = formulae.size();
1370 
1371  make_newline = false;
1372  for(Index nf = 0; nf < formulae.size(); nf++) {
1373  if(!formulae[nf].size())
1374  continue;
1375  make_newline = true;
1376  orbit_method_names[lf + nf] = "eval_bfunc_" + std::to_string(np) + "_" + std::to_string(no) + "_" + std::to_string(nf);
1377  private_def_stream <<
1378  indent << " double " << orbit_method_names[lf + nf] << "() const;\n";
1379 
1380  bfunc_imp_stream <<
1381  indent << "double " << class_name << "::" << orbit_method_names[lf + nf] << "() const{\n" <<
1382  indent << " return " << formulae[nf] << ";\n" <<
1383  indent << "}\n";
1384  }
1385  if(make_newline) {
1386  bfunc_imp_stream << '\n';
1387  private_def_stream << '\n';
1388  }
1389  make_newline = false;
1390 
1391  // loop over flowers (i.e., basis sites of prim)
1392  const SiteOrbitBranch &asym_unit(tree.asym_unit());
1393  for(Index na = 0; na < asym_unit.size(); na++) {
1394  for(Index ne = 0; ne < asym_unit[na].size(); ne++) {
1395  Index nb = asym_unit[na][ne][0].basis_ind();
1396  auto nlist_index = find_index(nlist.sublat_indices(), nb);
1397  if(nlist_index != nlist.sublat_indices().size()) {
1398  formulae = tree[np][no].flower_function_cpp_strings(labelers, nlist_index);
1399  for(Index nf = 0; nf < formulae.size(); nf++) {
1400  if(!formulae[nf].size())
1401  continue;
1402  make_newline = true;
1403  flower_method_names[nb][lf + nf] = "site_eval_at_" + std::to_string(nb) + "_bfunc_" + std::to_string(np) + "_" + std::to_string(no) + "_" + std::to_string(nf);
1404  private_def_stream <<
1405  indent << " double " << flower_method_names[nb][lf + nf] << "() const;\n";
1406 
1407  bfunc_imp_stream <<
1408  indent << "double " << class_name << "::" << flower_method_names[nb][lf + nf] << "() const{\n" <<
1409  indent << " return " << formulae[nf] << ";\n" <<
1410  indent << "}\n";
1411 
1412  }
1413  }
1414  if(make_newline) {
1415  bfunc_imp_stream << '\n';
1416  private_def_stream << '\n';
1417  }
1418  make_newline = false;
1419 
1420  // Very configuration-centric -> Find a way to move this block to OccupationDoFEnvironment:
1421  formulae.resize(formulae.size(), std::string());
1422  // loop over site basis functions
1423  const BasisSet &site_basis(asym_unit[na][ne].clust_basis);
1424  for(Index nsbf = 0; nsbf < site_basis.size(); nsbf++) {
1425  std::string delta_prefix = "(m_occ_func_" + std::to_string(nb) + "_" + std::to_string(nsbf) + "[occ_f] - m_occ_func_" + std::to_string(nb) + "_" + std::to_string(nsbf) + "[occ_i])";
1426 
1427  if(nlist_index != nlist.sublat_indices().size()) {
1428  tformulae = tree[np][no].delta_occfunc_flower_function_cpp_strings(site_basis, labelers, nlist_index, nb, nsbf);
1429  for(Index nf = 0; nf < tformulae.size(); nf++) {
1430  if(!tformulae[nf].size())
1431  continue;
1432 
1433  if(formulae[nf].size())
1434  formulae[nf] += " + ";
1435 
1436  formulae[nf] += delta_prefix;
1437 
1438  if(tformulae[nf] == "1" || tformulae[nf] == "(1)")
1439  continue;
1440 
1441  formulae[nf] += "*";
1442  formulae[nf] += tformulae[nf];
1443  //formulae[nf] += ")";
1444  }
1445  }
1446  }
1447  for(Index nf = 0; nf < formulae.size(); nf++) {
1448  if(!formulae[nf].size())
1449  continue;
1450  make_newline = true;
1451 
1452  dflower_method_names[nb][lf + nf] = "delta_site_eval_at_" + std::to_string(nb) + "_bfunc_" + std::to_string(np) + "_" + std::to_string(no) + "_" + std::to_string(nf);
1453  private_def_stream <<
1454  indent << " double " << dflower_method_names[nb][lf + nf] << "(int occ_i, int occ_f) const;\n";
1455 
1456  bfunc_imp_stream <<
1457  indent << "double " << class_name << "::" << dflower_method_names[nb][lf + nf] << "(int occ_i, int occ_f) const{\n" <<
1458  indent << " return " << formulae[nf] << ";\n" <<
1459  indent << "}\n";
1460  }
1461  if(make_newline) {
1462  bfunc_imp_stream << '\n';
1463  private_def_stream << '\n';
1464  }
1465  make_newline = false;
1466  // \End Configuration specific part
1467  }
1468  }//\End loop over flowers
1469 
1470  lf += tlf;
1471  }
1472  }//Finished writing method definitions and implementations for basis functions
1473 
1474  //clean up:
1475  for(Index nl = 0; nl < labelers.size(); nl++)
1476  delete labelers[nl];
1477  labelers.clear();
1478 
1479 
1480  // Write constructor
1481  interface_imp_stream <<
1482  indent << class_name << "::" << class_name << "() :\n" <<
1483  indent << " Clexulator_impl::Base(" << nlist.size() << ", " << N_corr << ") {\n";
1484 
1485  dof_manager.print_to_clexulator_constructor(interface_imp_stream, tree, indent + " ");
1486 
1487  for(Index nf = 0; nf < orbit_method_names.size(); nf++) {
1488  if(orbit_method_names[nf].size() == 0)
1489  interface_imp_stream <<
1490  indent << " m_orbit_func_list[" << nf << "] = &" << class_name << "::zero_func;\n";
1491  else
1492  interface_imp_stream <<
1493  indent << " m_orbit_func_list[" << nf << "] = &" << class_name << "::" << orbit_method_names[nf] << ";\n";
1494  }
1495  interface_imp_stream << "\n\n";
1496 
1497  for(Index nb = 0; nb < flower_method_names.size(); nb++) {
1498  for(Index nf = 0; nf < flower_method_names[nb].size(); nf++) {
1499  if(flower_method_names[nb][nf].size() == 0)
1500  interface_imp_stream <<
1501  indent << " m_flower_func_lists[" << nb << "][" << nf << "] = &" << class_name << "::zero_func;\n";
1502  else
1503  interface_imp_stream <<
1504  indent << " m_flower_func_lists[" << nb << "][" << nf << "] = &" << class_name << "::" << flower_method_names[nb][nf] << ";\n";
1505  }
1506  interface_imp_stream << "\n\n";
1507  }
1508 
1509  for(Index nb = 0; nb < dflower_method_names.size(); nb++) {
1510  for(Index nf = 0; nf < dflower_method_names[nb].size(); nf++) {
1511  if(dflower_method_names[nb][nf].size() == 0)
1512  interface_imp_stream <<
1513  indent << " m_delta_func_lists[" << nb << "][" << nf << "] = &" << class_name << "::zero_func;\n";
1514  else
1515  interface_imp_stream <<
1516  indent << " m_delta_func_lists[" << nb << "][" << nf << "] = &" << class_name << "::" << dflower_method_names[nb][nf] << ";\n";
1517  }
1518  interface_imp_stream << "\n\n";
1519  }
1520 
1521  // Write weight matrix used for the neighbor list
1523  interface_imp_stream << indent << " m_weight_matrix.row(0) << " << W(0, 0) << ", " << W(0, 1) << ", " << W(0, 2) << ";\n";
1524  interface_imp_stream << indent << " m_weight_matrix.row(1) << " << W(1, 0) << ", " << W(1, 1) << ", " << W(1, 2) << ";\n";
1525  interface_imp_stream << indent << " m_weight_matrix.row(2) << " << W(2, 0) << ", " << W(2, 1) << ", " << W(2, 2) << ";\n\n";
1526 
1527  // Write neighborhood of UnitCellCoord
1528  // expand the nlist to contain 'global_orbitree' (all that is needed for now)
1529  std::set<UnitCellCoord> nbors;
1530  neighborhood(std::inserter(nbors, nbors.begin()), tree, prim, TOL);
1531 
1532  /*
1533  for(auto it = nbors.begin(); it != nbors.end(); ++it) {
1534  interface_imp_stream << indent << " m_neighborhood.insert(UnitCellCoord("
1535  << it->sublat() << ", "
1536  << it->unitcell(0) << ", "
1537  << it->unitcell(1) << ", "
1538  << it->unitcell(2) << "));\n";
1539  }
1540  */
1541 
1542  interface_imp_stream << indent << " m_neighborhood = std::set<UnitCellCoord> {\n";
1543  auto it = nbors.begin();
1544  while(it != nbors.end()) {
1545  interface_imp_stream << indent << " {UnitCellCoord("
1546  << it->sublat() << ", "
1547  << it->unitcell(0) << ", "
1548  << it->unitcell(1) << ", "
1549  << it->unitcell(2) << ")}";
1550  ++it;
1551  if(it != nbors.end()) {
1552  interface_imp_stream << ",";
1553  }
1554  interface_imp_stream << "\n";
1555  }
1556  interface_imp_stream << indent << " };\n";
1557  interface_imp_stream << "\n\n";
1558 
1559  interface_imp_stream << indent << " m_orbit_neighborhood.resize(corr_size());\n";
1560  Index lno = 0;
1561  for(Index nb = 0; nb < tree.size(); ++nb) {
1562  for(Index no = 0; no < tree[nb].size(); ++no) {
1563  std::set<UnitCellCoord> orbit_nbors;
1564  orbit_neighborhood(std::inserter(orbit_nbors, orbit_nbors.begin()), tree, prim, nb, no, TOL);
1565 
1566  Index proto_index = lno;
1567  /*
1568  for(auto it = orbit_nbors.begin(); it != orbit_nbors.end(); ++it) {
1569  interface_imp_stream << indent << " m_orbit_neighborhood[" << lno << "].insert(UnitCellCoord("
1570  << it->sublat() << ", "
1571  << it->unitcell(0) << ", "
1572  << it->unitcell(1) << ", "
1573  << it->unitcell(2) << "));\n";
1574  }
1575  */
1576  interface_imp_stream << indent << " m_orbit_neighborhood[" << lno << "] = std::set<UnitCellCoord> {\n";
1577  auto it = orbit_nbors.begin();
1578  while(it != orbit_nbors.end()) {
1579  interface_imp_stream << indent << " {UnitCellCoord("
1580  << it->sublat() << ", "
1581  << it->unitcell(0) << ", "
1582  << it->unitcell(1) << ", "
1583  << it->unitcell(2) << ")}";
1584  ++it;
1585  if(it != orbit_nbors.end()) {
1586  interface_imp_stream << ",";
1587  }
1588  interface_imp_stream << "\n";
1589  }
1590  interface_imp_stream << indent << " };\n";
1591  ++lno;
1592  for(Index nf = 1; nf < tree.prototype(nb, no).clust_basis.size(); ++nf) {
1593  interface_imp_stream << indent << " m_orbit_neighborhood[" << lno << "] = m_orbit_neighborhood[" << proto_index << "];\n";
1594  ++lno;
1595  }
1596  interface_imp_stream << "\n";
1597 
1598  }
1599  }
1600 
1601 
1602  interface_imp_stream <<
1603  indent << "}\n\n";
1604 
1605  // Write destructor
1606 
1607  interface_imp_stream <<
1608  indent << class_name << "::~" << class_name << "(){\n" <<
1609 
1610  indent << " //nothing here for now\n" <<
1611 
1612  indent << "}\n\n";
1613 
1614  // Write evaluation methods
1615 
1616  interface_imp_stream <<
1617  indent << "/// \\brief Calculate contribution to global correlations from one unit cell\n" <<
1618  indent << "void " << class_name << "::calc_global_corr_contribution(double *corr_begin) const {\n" <<
1619  indent << " for(size_type i=0; i<corr_size(); i++){\n" <<
1620  indent << " *(corr_begin+i) = (this->*m_orbit_func_list[i])();\n" <<
1621  indent << " }\n" <<
1622  indent << "}\n\n" <<
1623 
1624  indent << "/// \\brief Calculate contribution to select global correlations from one unit cell\n" <<
1625  indent << "void " << class_name << "::calc_restricted_global_corr_contribution(double *corr_begin, size_type const* ind_list_begin, size_type const* ind_list_end) const {\n" <<
1626  indent << " for(; ind_list_begin<ind_list_end; ind_list_begin++){\n" <<
1627  indent << " *(corr_begin+*ind_list_begin) = (this->*m_orbit_func_list[*ind_list_begin])();\n" <<
1628  indent << " }\n" <<
1629  indent << "}\n\n" <<
1630 
1631  indent << "/// \\brief Calculate point correlations about basis site 'b_index'\n" <<
1632  indent << "void " << class_name << "::calc_point_corr(int b_index, double *corr_begin) const {\n" <<
1633  indent << " for(size_type i=0; i<corr_size(); i++){\n" <<
1634  indent << " *(corr_begin+i) = (this->*m_flower_func_lists[b_index][i])();\n" <<
1635  indent << " }\n" <<
1636  indent << "}\n\n" <<
1637 
1638  indent << "/// \\brief Calculate select point correlations about basis site 'b_index'\n" <<
1639  indent << "void " << class_name << "::calc_restricted_point_corr(int b_index, double *corr_begin, size_type const* ind_list_begin, size_type const* ind_list_end) const {\n" <<
1640  indent << " for(; ind_list_begin<ind_list_end; ind_list_begin++){\n" <<
1641  indent << " *(corr_begin+*ind_list_begin) = (this->*m_flower_func_lists[b_index][*ind_list_begin])();\n" <<
1642  indent << " }\n" <<
1643  indent << "}\n\n" <<
1644 
1645  indent << "/// \\brief Calculate the change in point correlations due to changing an occupant\n" <<
1646  indent << "void " << class_name << "::calc_delta_point_corr(int b_index, int occ_i, int occ_f, double *corr_begin) const {\n" <<
1647  indent << " for(size_type i=0; i<corr_size(); i++){\n" <<
1648  indent << " *(corr_begin+i) = (this->*m_delta_func_lists[b_index][i])(occ_i, occ_f);\n" <<
1649  indent << " }\n" <<
1650  indent << "}\n\n" <<
1651 
1652  indent << "/// \\brief Calculate the change in select point correlations due to changing an occupant\n" <<
1653  indent << "void " << class_name << "::calc_restricted_delta_point_corr(int b_index, int occ_i, int occ_f, double *corr_begin, size_type const* ind_list_begin, size_type const* ind_list_end) const {\n" <<
1654  indent << " for(; ind_list_begin<ind_list_end; ind_list_begin++){\n" <<
1655  indent << " *(corr_begin+*ind_list_begin) = (this->*m_delta_func_lists[b_index][*ind_list_begin])(occ_i, occ_f);\n" <<
1656  indent << " }\n" <<
1657  indent << "}\n\n";
1658 
1659 
1660  // PUT EVERYTHING TOGETHER
1661  stream <<
1662  "#include <cstddef>\n" <<
1663  "#include \"casm/clex/Clexulator.hh\"\n" <<
1664  "\n\n\n" <<
1665  "/****** CLEXULATOR CLASS FOR PRIM ******" << std::endl;
1666 
1667  jsonParser json;
1668  write_prim(prim, json, FRAC);
1669  stream << json;
1670 
1671  stream <<
1672  "**/\n\n\n" <<
1673 
1674  "/// \\brief Returns a Clexulator_impl::Base* owning a " << class_name << "\n" <<
1675  "extern \"C\" CASM::Clexulator_impl::Base* make_" + class_name << "();\n\n" <<
1676 
1677  "namespace CASM {\n\n" <<
1678 
1679 
1680  indent << "class " << class_name << " : public Clexulator_impl::Base {\n\n" <<
1681 
1682  indent << "public:\n\n" <<
1683  public_def_stream.str() << "\n" <<
1684 
1685  indent << "private:\n\n" <<
1686  private_def_stream.str() << "\n" <<
1687 
1688  indent << "};\n\n" << // close class definition
1689 
1690  indent <<
1691 
1692  "//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n" <<
1693 
1694  interface_imp_stream.str() <<
1695  bfunc_imp_stream.str() <<
1696  "}\n\n\n" << // close namespace
1697 
1698  "extern \"C\" {\n" <<
1699  indent << "/// \\brief Returns a Clexulator_impl::Base* owning a " << class_name << "\n" <<
1700  indent << "CASM::Clexulator_impl::Base* make_" + class_name << "() {\n" <<
1701  indent << " return new CASM::" + class_name + "();\n" <<
1702  indent << "}\n\n" <<
1703  "}\n" <<
1704 
1705  "\n";
1706  // EOF
1707 
1708  return;
1709  }
1710 
1711 
1712 }
bool m_vacancy_allowed
Definition: PrimClex.hh:60
CompositionConverter m_comp_converter
Definition: PrimClex.hh:72
Eigen::MatrixXd MatrixXd
Clexulator clexulator(const ClexDescription &key) const
Definition: PrimClex.cc:1030
bool has_orbitree(const ClexDescription &key) const
const Access to global orbitree
Definition: PrimClex.cc:983
fs::path eci(std::string property, std::string calctype, std::string ref, std::string bset, std::string eci) const
Returns path to eci.json.
void close()
Closes stream, and if not a failed write, removes "file" and renames "file.tmp" to "file"...
Definition: SafeOfstream.hh:81
boost::container::stable_vector< Supercell > & get_supercell_list()
Access entire supercell_list.
Definition: PrimClex.cc:299
Structure prim
Definition: PrimClex.hh:59
int amount_selected() const
Count over the number of configurations that are selected in all supercells.
Definition: PrimClex.cc:700
const SublatIndices & sublat_indices() const
pair of const_iterators over a range of indices of sublattices to include
std::string get_name() const
Return supercell name.
Definition: Supercell.cc:123
Specifies a particular cluster expansion.
void print_clexulator_member_definitions(std::ostream &stream, const SiteOrbitree &tree, const std::string &indent) const
Definition: DoFManager.cc:88
CompositionConverter curr
Definition: AppIO.hh:95
void write_config_list(std::set< std::string > scel_to_delete={})
Definition: PrimClex.cc:450
static std::pair< std::string, Index > split_name(std::string configname)
Split configuration name string into scelname and config index.
ClustJsonHelper< ValueType > jsonHelper(ValueType &_value, const Structure &_struc, double tol=TOL)
Definition: jsonClust.hh:62
fs::path get_config_list_path() const
Return config_list.json file path.
Definition: PrimClex.cc:220
void print_clexulator_private_method_definitions(std::ostream &stream, const SiteOrbitree &tree, const std::string &indent) const
Definition: DoFManager.cc:96
fs::path root
Definition: PrimClex.hh:54
ProjectSettings m_settings
Definition: PrimClex.hh:57
void from_json(ClexDescription &desc, const jsonParser &json)
bool has_clexulator(const ClexDescription &key) const
Definition: PrimClex.cc:1018
Eigen::MatrixXd shift_vectors() const
private:
Definition: PrimClex.cc:973
Eigen::Matrix3l nlist_weight_matrix() const
Get neighbor list weight matrix.
Index size() const
Definition: Array.hh:145
fs::path composition_axes() const
Return composition axes file path.
fs::path SCEL() const
Return SCEL path.
const DirectoryStructure & dir() const
Definition: PrimClex.hh:112
void resize_neighborhood(Index nlist_size)
Definition: DoFManager.cc:68
std::string generate_name(const Eigen::Matrix3i &transf_mat)
Definition: Supercell.cc:1276
const SymGroup & point_group() const
Definition: Structure.cc:101
bool is_vacancy(const std::string &name)
A vacancy is any Specie/Molecule with (name == "VA" || name == "va" || name == "Va") ...
Definition: Molecule.hh:27
ConfigIterator< Configuration, PrimClex > config_iterator
Definition: PrimClex.hh:85
fs::path get_path() const
Return casm project directory path.
Definition: PrimClex.cc:202
Structure specifies the lattice and atomic basis of a crystal.
Definition: Structure.hh:29
void print_compiler_settings_summary(Log &log) const
Print summary of compiler settings, as for 'casm settings -l'.
Data structure for holding supercell enumeration properties.
void resize(Index new_N)
Definition: Array.hh:468
void print_clexulator_public_method_definitions(std::ostream &stream, const SiteOrbitree &tree, const std::string &indent) const
Definition: DoFManager.cc:112
Unit Cell Coordinates.
bool has_composition_axes() const
check if CompositionConverter object initialized
Definition: PrimClex.cc:231
void refresh(bool read_settings=false, bool read_composition=false, bool read_chem_ref=false, bool read_configs=false, bool clear_clex=false)
Reload PrimClex data from settings.
Definition: PrimClex.cc:90
void set_composition_axes(const CompositionConverter &_converter)
Sets the composition axes.
Definition: PrimClex.cc:749
void write_prim(const BasicStructure< Site > &prim, fs::path filename, COORD_TYPE mode)
Write prim.json to file.
Definition: AppIO.cc:107
Index find_index(Iterator begin, Iterator end, const T &value)
Equivalent to std::distance(begin, std::find(begin, end, value))
Definition: algorithm.hh:16
std::map< ClexDescription, ECIContainer > m_eci
Definition: PrimClex.hh:346
ReturnArray< FunctionVisitor * > get_function_label_visitors() const
Definition: DoFManager.cc:76
ConfigList & get_config_list()
Definition: Supercell.hh:279
bool read(std::istream &stream)
Reads json from the stream.
Definition: jsonParser.cc:165
const std::set< int > & nlist_sublat_indices() const
Get set of sublattice indices to include in neighbor lists.
Main CASM namespace.
Definition: complete.cpp:8
Write to a temporary file to ensure a good write, then rename.
Definition: SafeOfstream.hh:28
std::string to_string(ENUM val)
Return string representation of enum class.
Definition: EnumIO.hh:83
const Lattice & lattice() const
fs::ofstream & ofstream()
Access underlying stream.
Definition: SafeOfstream.hh:76
const double TOL
Represents a supercell of the primitive parent crystal structure.
Definition: Supercell.hh:37
ECIContainer read_eci(const fs::path &filepath)
Read eci.json file from specified path.
const Eigen::Matrix3d & lat_column_mat() const
3x3 matrix with lattice vectors as its columne
Definition: Lattice.hh:104
std::string name() const
Return project name.
Definition: PrimClex.cc:194
Unit Cell Indices.
const_iterator cend() const
Returns const_iterator to end of JSON object or JSON array.
Definition: jsonParser.cc:480
Log & log() const
Definition: Log.hh:255
config_iterator selected_config_end()
Configuration iterator: end.
Definition: PrimClex.cc:424
config_iterator config_begin()
Configuration iterator: begin.
Definition: PrimClex.cc:371
void generate_supercells(const ScelEnumProps &enum_props)
Use the given CSPECS.
Definition: PrimClex.cc:492
config_iterator config_end()
Configuration iterator: end.
Definition: PrimClex.cc:379
boost::container::stable_vector< Supercell > supercell_list
Contains all the supercells that were involved in the enumeration.
Definition: PrimClex.hh:66
BasicStructure< Site > read_prim(fs::path filename)
Definition: AppIO.cc:11
void print(std::ostream &stream, unsigned int indent=2, unsigned int prec=12) const
Print json to stream.
Definition: jsonParser.cc:185
std::vector< std::string > get_struc_molecule_name() const
Returns an Array of each possible Molecule in this Structure.
Definition: Structure.cc:166
bool has_chemical_reference() const
check if ChemicalReference object initialized
Definition: PrimClex.cc:245
Index basis_set_size() const
Count number of basis functions at each orbit and sum result.
void open(fs::path name, std::string tmp_ext="tmp")
Opens "file.tmp" for writing, with intended final target "file".
Definition: SafeOfstream.hh:62
ConfigIterator< const Configuration, const PrimClex > config_const_iterator
Definition: PrimClex.hh:86
bool vacancy_allowed() const
returns true if vacancy are an allowed species
Definition: PrimClex.cc:284
void construct(const std::string &what)
Definition: Log.hh:36
void custom(const std::string &what)
Definition: Log.hh:96
std::string name() const
Get project name.
const Eigen::Matrix3d & inv_lat_column_mat() const
Inverse of Lattice::lat_column_mat() It is the transformation matrix 'C2F', such that f = C2F * c whe...
Definition: Lattice.hh:113
void clear()
Definition: Array.hh:216
bool set_crystallography_tol(double _tol)
Set crystallography tolerance.
GenericOrbitree< SiteCluster > SiteOrbitree
Definition: Clex.hh:14
config_const_iterator selected_config_cend() const
const Configuration iterator: end
Definition: PrimClex.cc:438
size_type erase(const std::string &name)
Erase key:value pair from an object.
Definition: jsonParser.cc:506
double crystallography_tol() const
Definition: PrimClex.hh:124
void set_nlist_ind(const Structure &prim, SiteOrbitree &tree, const PrimNeighborList &nlist, double xtal_tol)
Definition: PrimClex.cc:1143
const MasterSymGroup & factor_group() const
Definition: Structure.cc:94
Read/modify settings of an already existing CASM project.
fs::path project_settings() const
Return project_settings.json path.
config_const_iterator selected_config_cbegin() const
const Configuration iterator: begin
Definition: PrimClex.cc:430
std::map< ClexDescription, SiteOrbitree > m_orbitree
Definition: PrimClex.hh:344
EigenIndex Index
For long integer indexing:
OutputIterator neighborhood(OutputIterator result, const TreeType &tree, const StrucType &struc, double tol)
Iterate over all sites in an orbitree and insert a UnitCellCoord.
Definition: Orbitree.hh:314
Evaluates correlations.
Definition: Clexulator.hh:240
void read_supercells(std::istream &stream)
Definition: PrimClex.cc:605
Lattice canonical_equivalent_lattice(const Lattice &in_lat, const SymGroup &point_grp, double compare_tol)
Find the niggli, most standard oriented version of the given orbit (defined by the given SymGroup) of...
Definition: Niggli.cc:276
void set_bspecs(const jsonParser &_bspecs)
Definition: Orbitree.hh:108
Array< CoordType > basis
Lattice vectors that specifies periodicity of the crystal.
config_const_iterator config_cend() const
const Configuration iterator: end
Definition: PrimClex.cc:407
DirectoryStructure m_dir
Definition: PrimClex.hh:56
ProjectSettings & settings()
Definition: PrimClex.hh:116
config_iterator selected_config_begin()
Configuration iterator: begin.
Definition: PrimClex.cc:413
PrimClex is the top-level data structure for a CASM project.
Definition: PrimClex.hh:52
Index m_vacancy_index
Definition: PrimClex.hh:61
const CompositionConverter & composition_axes() const
const Access CompositionConverter object
Definition: PrimClex.cc:237
bool is_supercell_of(const Lattice &tile, Eigen::Matrix3d &multimat, double _tol=TOL) const
Matrix that relates two lattices (e.g., strain or slat)
Definition: Lattice.cc:655
UnitCell & unitcell()
ChemicalReference read_chemical_reference(fs::path filename, const Structure &prim, double tol)
Read chemical reference states from JSON file.
Definition: AppIO.cc:212
void set_id(Index id)
Definition: Supercell.hh:355
Index add_canonical_supercell(const Lattice &superlat)
Definition: PrimClex.cc:511
const ChemicalReference & chemical_reference() const
const Access ChemicalReference object
Definition: PrimClex.cc:251
double lin_alg_tol() const
Definition: PrimClex.hh:128
config_const_iterator config_cbegin() const
const Configuration iterator: begin
Definition: PrimClex.cc:399
PrimNeighborList & nlist() const
Access to the primitive neighbor list.
Definition: PrimClex.cc:266
const Configuration & configuration(const std::string &configname) const
access configuration by name (of the form "scellname/[NUMBER]", e.g., ("SCEL1_1_1_1_0_0_0/0") ...
Definition: PrimClex.cc:347
bool has_eci(const ClexDescription &key) const
Definition: PrimClex.cc:1065
void print_supercells(std::set< std::string > scel_to_delete={}) const
Definition: PrimClex.cc:557
bool m_has_composition_axes
Definition: PrimClex.hh:71
notstd::cloneable_ptr< ChemicalReference > m_chem_ref
Definition: PrimClex.hh:76
Index add_supercell(const Lattice &superlat)
Definition: PrimClex.cc:550
bool is_integer(const Eigen::MatrixBase< Derived > &M, double tol)
Check if Eigen::Matrix is integer.
ConfigIO::GenericConfigFormatter< std::string > configname()
Constructs DataFormmaterDictionary containing all Configuration DatumFormatters.
Definition: ConfigIO.cc:340
notstd::cloneable_ptr< PrimNeighborList > m_nlist
Definition: PrimClex.hh:80
bool all_in(const Array &superset) const
Definition: Array.hh:664
Index vacancy_index() const
returns the index of vacancies in composition vectors
Definition: PrimClex.cc:290
Eigen::Matrix3d Matrix3d
jsonParser & put_obj()
Puts new empty JSON object.
Definition: jsonParser.hh:276
size_type size() const
size of the neighborhood of unit cells
Definition: NeighborList.cc:77
Convert between number of species per unit cell and parametric composition.
const ClustType & prototype(Index np, Index no) const
Access prototype of orbit (np, no)
fs::path config_list() const
Return master config_list.json file path.
The PrimNeighborList gives the coordinates of UnitCell that are neighbors of the origin UnitCell...
Definition: NeighborList.hh:24
const Supercell & get_supercell(Index i) const
const Access supercell by index
Definition: PrimClex.cc:311
bool contains(const std::string &name) const
Return true if JSON object contains 'name'.
Definition: jsonParser.cc:500
void print_clexulator(const Structure &prim, SiteOrbitree &tree, const PrimNeighborList &nlist, std::string class_name, std::ostream &stream, double xtal_tol)
Print clexulator.
Definition: PrimClex.cc:1219
void warning(const std::string &what)
Definition: Log.hh:81
void print_to_clexulator_constructor(std::ostream &stream, const SiteOrbitree &tree, const std::string &indent) const
Definition: DoFManager.cc:128
PrimClex(const Structure &_prim, const Logging &logging=Logging())
Initial construction of a PrimClex, from a primitive Structure.
Definition: PrimClex.cc:21
void error(const std::string &what)
Definition: Log.hh:86
Eigen::CwiseUnaryOp< decltype(std::ptr_fun(boost::math::iround< typename Derived::Scalar >)), const Derived > iround(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd to Eigen::MatrixXi.
DoFManager holds multiple DoFEnvironments, and provides a simple interface for adding and managing Do...
Definition: DoFManager.hh:13
Definition: Log.hh:9
const Eigen::Matrix3i & get_transf_mat() const
Definition: Supercell.hh:263
void generate_clust_bases(std::vector< BasisSet const * > const &global_args, Index max_poly_order=-1)
get clust_basis for all equivalent clusters
void read_config_list()
Definition: PrimClex.cc:680
Matrix3Type weight_matrix() const
Return the weighting matrix W used to define the canonical order.
Definition: NeighborList.cc:9
Eigen::Matrix3l Matrix3Type
Definition: NeighborList.hh:31
OutputIterator orbit_neighborhood(OutputIterator result, const TreeType &tree, const StrucType &struc, Index nb, Index no, double tol)
Iterate over all sites in an orbit and insert a UnitCellCoord.
Definition: Orbitree.hh:279
bool contains_supercell(std::string scellname, Index &index) const
Definition: PrimClex.cc:709
const ClexDescription & default_clex() const
std::map< ClexDescription, Clexulator > m_clexulator
Definition: PrimClex.hh:345
fs::path chemical_reference(std::string calctype, std::string ref) const
Return chemical reference file path.
SiteOrbitree make_orbitree(Structure &prim, const jsonParser &json, double _tol)
Make orbitree. For now specifically global.
Definition: PrimClex.cc:1097
bool almost_equal(const GenericCluster< CoordType > &LHS, const GenericCluster< CoordType > &RHS, double tol)
const GenericOrbitBranch< ClustType > & asym_unit() const
Definition: Orbitree.hh:227
const SiteOrbitree & orbitree(const ClexDescription &key) const
Definition: PrimClex.cc:996
void register_dofs(GenericOrbitree< ClustType > &tree) const
Definition: DoFManager.hh:192
void add_dof(const std::string &dof_name)
Definition: DoFManager.cc:32
void _init()
Initialization routines.
Definition: PrimClex.cc:49
Index size(Index np) const
Number of orbits in OrbitBranch 'np'.
Eigen::Matrix3i calc_transf_mat(const Lattice &superlat) const
Definition: PrimClex.cc:731
A Configuration represents the values of all degrees of freedom in a Supercell.
const Structure & get_prim() const
const Access to primitive Structure
Definition: PrimClex.cc:260
const ECIContainer & eci(const ClexDescription &key) const
Definition: PrimClex.cc:1076
Log & err_log() const
Definition: Log.hh:263
A sparse container of ECI values and their corresponding orbit indices.
Definition: ECIContainer.hh:12