CASM  1.1.0
A Clusters Approach to Statistical Mechanics
ClexBasisWriter_impl.hh
Go to the documentation of this file.
1 #ifndef CASM_ClexBasisWriter_impl
2 #define CASM_ClexBasisWriter_impl
3 
15 
16 // These are where ParamPackMixIns are defined -- only usage
18 
19 namespace CASM {
20 //*******************************************************************************************
22 template <typename OrbitType>
23 void ClexBasisWriter::print_clexulator(std::string class_name,
24  ClexBasis const &clex,
25  std::vector<OrbitType> const &_tree,
26  PrimNeighborList &_nlist,
27  std::ostream &stream, double xtal_tol) {
28  enum FuncStringType { func_declaration = 0, func_definition = 1 };
29 
30  Index N_corr = clex.n_functions();
31 
32  std::map<UnitCellCoord, std::set<UnitCellCoord> > nhood =
33  ClexBasisWriter_impl::dependency_neighborhood(_tree.begin(), _tree.end());
34 
35  Index N_flower = nhood.size();
36  for (auto const &nbor : nhood)
37  N_flower = max(_nlist.neighbor_index(nbor.first) + 1, N_flower);
38 
39  std::stringstream bfunc_imp_stream, bfunc_def_stream;
40 
41  std::string indent(2, ' ');
42 
43  std::stringstream param_pack_stream;
44  print_param_pack(class_name, clex, _tree, _nlist, param_pack_stream, indent);
45 
46  std::string uclass_name;
47  for (Index i = 0; i < class_name.size(); i++)
48  uclass_name.push_back(std::toupper(class_name[i]));
49 
50  std::string private_declarations =
52  class_name, clex, *m_param_pack_mix_in, _orbit_func_traits(),
53  N_flower, indent + " ");
54 
55  private_declarations +=
57  class_name, clex, indent + " ");
58 
59  std::string public_declarations =
61  class_name, clex, indent + " ");
62 
63  // linear function index
64  Index lf = 0;
65 
66  std::vector<std::unique_ptr<FunctionVisitor> > const &visitors(
68  // std::cout << "Initialized " << visitors.size() << " visitors \n";
69 
70  std::vector<std::string> orbit_method_names(N_corr, "zero_func");
71 
72  std::vector<std::vector<std::string> > flower_method_names(
73  N_flower, std::vector<std::string>(N_corr, "zero_func"));
74 
75  // this is very configuration-centric
76  std::vector<std::vector<std::string> > dflower_method_names(
77  N_flower, std::vector<std::string>(N_corr, "zero_func"));
78 
79  // temporary storage for formula
80  std::vector<std::string> formulae, tformulae;
81 
82  // loop over orbits
83  for (Index no = 0; no < _tree.size(); no++) {
84  if (_tree[no].prototype().size() == 0)
85  bfunc_imp_stream << indent << "// Basis functions for empty cluster:\n";
86  else {
87  bfunc_imp_stream << indent << "/**** Basis functions for orbit " << no
88  << "****\n";
89  Log l(bfunc_imp_stream);
90  ProtoSitesPrinter().print(_tree[no].prototype(), l);
91  bfunc_imp_stream << indent << "****/\n";
92  }
93 
94  auto orbit_method_namer = [lf, no, &orbit_method_names](
95  Index nb, Index nf) -> std::string {
96  orbit_method_names[lf + nf] =
97  "eval_bfunc_" + std::to_string(no) + "_" + std::to_string(nf);
98  return orbit_method_names[lf + nf];
99  };
100 
101  std::tuple<std::string, std::string> orbit_functions =
103  class_name, clex.bset_orbit(no), _tree[no], orbit_method_namer,
104  _nlist, visitors, indent);
105 
106  bfunc_def_stream << std::get<func_declaration>(orbit_functions);
107  bfunc_imp_stream << std::get<func_definition>(orbit_functions);
108 
109  auto flower_method_namer = [lf, no, &flower_method_names](
110  Index nb, Index nf) -> std::string {
111  flower_method_names[nb][lf + nf] =
112  "site_eval_bfunc_" + std::to_string(no) + "_" + std::to_string(nf) +
113  "_at_" + std::to_string(nb);
114  return flower_method_names[nb][lf + nf];
115  };
116 
117  std::tuple<std::string, std::string> flower_functions =
119  class_name, clex.bset_orbit(no), _tree[no], flower_method_namer,
120  nhood, _nlist, visitors, indent);
121 
122  bfunc_def_stream << std::get<func_declaration>(flower_functions);
123  bfunc_imp_stream << std::get<func_definition>(flower_functions);
124 
125  auto dflower_method_namer = [lf, no, &dflower_method_names](
126  Index nb, Index nf) -> std::string {
127  dflower_method_names[nb][lf + nf] =
128  "site_deval_bfunc_" + std::to_string(no) + "_" + std::to_string(nf) +
129  "_at_" + std::to_string(nb);
130  return dflower_method_names[nb][lf + nf];
131  };
132 
133  // Hard-coded for occupation currently... this should be encoded in
134  // DoFTraits instead.
135  std::string dof_key("occ");
136  OccFuncLabeler site_prefactor_labeler(
137  "(m_occ_func_%b_%f[occ_f] - m_occ_func_%b_%f[occ_i])");
138 
139  auto site_bases_iter = clex.site_bases().find(dof_key);
140  if (site_bases_iter != clex.site_bases().end()) {
141  std::tuple<std::string, std::string> dflower_functions =
143  class_name, clex.bset_orbit(no), site_bases_iter->second,
144  _tree[no], dflower_method_namer, nhood, _nlist, visitors,
145  site_prefactor_labeler, indent);
146 
147  bfunc_def_stream << std::get<func_declaration>(dflower_functions);
148  bfunc_imp_stream << std::get<func_definition>(dflower_functions);
149  }
150  // else, no dflower functions get printed, and they all revert to
151  // zero_func()
152 
153  lf += clex.bset_orbit(no)[0].size();
154  } // Finished writing method definitions and definitions for basis functions
155 
156  std::string constructor_definition =
158  class_name, clex, _tree, nhood, _nlist, *m_param_pack_mix_in,
159  orbit_method_names, flower_method_names, dflower_method_names,
160  indent);
161 
162  std::string interface_declaration =
164  class_name, clex, *m_param_pack_mix_in, indent);
165 
166  std::string prepare_methods_definition =
168  class_name, clex, _tree, _orbit_func_traits(), nhood, _nlist, indent);
169 
170  prepare_methods_definition +=
172  class_name, clex, _tree, _orbit_func_traits(), nhood, _nlist, indent);
173 
174  jsonParser json_prim;
175  write_prim(clex.prim(), json_prim, FRAC);
176 
177  // TODO: should this be ClexBasisSpecs or BasisFunctionSpecs?
178  jsonParser basis_set_specs_json;
179  to_json(clex.basis_set_specs(), basis_set_specs_json, clex.prim(),
180  clex.dof_dict());
181 
182  // PUT EVERYTHING TOGETHER
183  stream
184  << "#include <cstddef>\n"
185  << "#include \"casm/clex/Clexulator.hh\"\n"
186  << "#include \"casm/clex/BasicClexParamPack.hh\"\n"
187  << "#include \"casm/global/eigen.hh\"\n"
188  << (m_param_pack_mix_in->cpp_includes_string()) << "\n"
189  << "\n\n\n"
190 
191  << "/****** PROJECT SPECIFICATIONS ******\n\n"
192 
193  << " ****** prim.json ******\n\n"
194  << json_prim << "\n\n"
195  << " ****** bspecs.json ******\n\n"
196  << basis_set_specs_json << "\n\n"
197  << "**/\n\n\n"
198 
199  << "/// \\brief Returns a Clexulator_impl::Base* owning a " << class_name
200  << "\n"
201  << "extern \"C\" CASM::Clexulator_impl::Base *make_" + class_name
202  << "();\n\n"
203 
204  << "namespace CASM {\n\n"
205 
206  << " /****** GENERATED CLEXPARAMPACK DEFINITION ******/\n\n"
207 
208  << param_pack_stream.str() << "\n\n"
209 
210  << " /****** GENERATED CLEXULATOR DEFINITION ******/\n\n"
211 
212  << indent << "class " << class_name
213  << " : public Clexulator_impl::Base {\n\n"
214 
215  << indent << "public:\n\n"
216  << public_declarations << "\n"
217  << bfunc_def_stream.str() << "\n"
218 
219  << indent << "private:\n\n"
220  << private_declarations << "\n"
221 
222  << indent << "};\n\n" // close class definition
223 
224  << indent
225 
226  << "//"
227  "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n"
228 
229  << constructor_definition << "\n"
230  << interface_declaration << "\n"
231  << prepare_methods_definition << "\n"
232  << bfunc_imp_stream.str() << "}\n\n\n" // close namespace
233 
234  << "extern \"C\" {\n"
235  << indent << "/// \\brief Returns a Clexulator_impl::Base* owning a "
236  << class_name << "\n"
237  << indent << "CASM::Clexulator_impl::Base *make_" + class_name << "() {\n"
238  << indent << " return new CASM::" + class_name + "();\n"
239  << indent << "}\n\n"
240  << "}\n"
241 
242  << "\n";
243  // EOF
244 
245  return;
246 }
247 
248 template <typename OrbitType>
249 void ClexBasisWriter::print_param_pack(std::string clexclass_name,
250  ClexBasis const &clex,
251  std::vector<OrbitType> const &_tree,
252  PrimNeighborList &_nlist,
253  std::ostream &stream,
254  std::string const &_indent) const {
255  stream << (m_param_pack_mix_in->cpp_definitions_string(_indent)) << '\n'
256  << _indent << "typedef " << (m_param_pack_mix_in->name())
257  << " ParamPack;\n";
258 }
259 namespace ClexBasisWriter_impl {
260 
261 template <typename OrbitType>
262 std::tuple<std::string, std::string> clexulator_orbit_function_strings(
263  std::string const &class_name, ClexBasis::BSetOrbit const &_bset_orbit,
264  OrbitType const &_clust_orbit,
265  std::function<std::string(Index, Index)> method_namer,
266  PrimNeighborList &_nlist,
267  std::vector<std::unique_ptr<FunctionVisitor> > const &visitors,
268  std::string const &indent) {
269  std::stringstream bfunc_def_stream;
270  std::stringstream bfunc_imp_stream;
271 
272  std::vector<std::string> formulae =
273  orbit_function_cpp_strings(_bset_orbit, _clust_orbit, _nlist, visitors);
274  std::string method_name;
275 
276  bool make_newline = false;
277  for (Index nf = 0; nf < formulae.size(); nf++) {
278  if (!formulae[nf].size()) continue;
279  make_newline = true;
280 
281  method_name = method_namer(0, nf);
282  bfunc_def_stream << indent << " template<typename Scalar>\n"
283  << indent << " Scalar " << method_name << "() const;\n";
284 
285  bfunc_imp_stream << indent << "template<typename Scalar>\n"
286  << indent << "Scalar " << class_name << "::" << method_name
287  << "() const {\n"
288  << indent << " return " << formulae[nf] << ";\n"
289  << indent << "}\n";
290  }
291  if (make_newline) {
292  bfunc_imp_stream << '\n';
293  bfunc_def_stream << '\n';
294  }
295  return std::tuple<std::string, std::string>(bfunc_def_stream.str(),
296  bfunc_imp_stream.str());
297 }
298 
299 //*******************************************************************************************
300 
301 template <typename OrbitType>
302 std::tuple<std::string, std::string> clexulator_flower_function_strings(
303  std::string const &class_name, ClexBasis::BSetOrbit const &_bset_orbit,
304  OrbitType const &_clust_orbit,
305  std::function<std::string(Index, Index)> method_namer,
306  std::map<UnitCellCoord, std::set<UnitCellCoord> > const &_nhood,
307  PrimNeighborList &_nlist,
308  std::vector<std::unique_ptr<FunctionVisitor> > const &visitors,
309  std::string const &indent) {
310  std::stringstream bfunc_def_stream, bfunc_imp_stream;
311  std::string method_name;
312  // loop over flowers (i.e., basis sites of prim)
313  bool make_newline = false;
314 
315  for (auto const &nbor : _nhood) {
316  make_newline = false;
317 
318  std::vector<std::string> formulae = flower_function_cpp_strings(
319  _bset_orbit, CASM_TMP::UnaryIdentity<BasisSet>(), _clust_orbit, _nhood,
320  _nlist, visitors, nbor.first);
321 
322  Index nbor_ind = _nlist.neighbor_index(nbor.first);
323 
324  for (Index nf = 0; nf < formulae.size(); nf++) {
325  if (!formulae[nf].size()) continue;
326  make_newline = true;
327 
328  method_name = method_namer(nbor_ind, nf);
329  bfunc_def_stream << indent << " template<typename Scalar>\n"
330  << indent << " Scalar " << method_name << "() const;\n";
331 
332  bfunc_imp_stream << indent << "template<typename Scalar>\n"
333  << indent << "Scalar " << class_name
334  << "::" << method_name << "() const {\n"
335  << indent << " return " << formulae[nf] << ";\n"
336  << indent << "}\n";
337  }
338  }
339  if (make_newline) {
340  bfunc_imp_stream << '\n';
341  bfunc_def_stream << '\n';
342  }
343 
344  return std::tuple<std::string, std::string>(bfunc_def_stream.str(),
345  bfunc_imp_stream.str());
346 }
347 
348 //*******************************************************************************************
349 
350 template <typename OrbitType>
351 std::tuple<std::string, std::string> clexulator_dflower_function_strings(
352  std::string const &class_name, ClexBasis::BSetOrbit const &_bset_orbit,
353  ClexBasis::BSetOrbit const &_site_bases, OrbitType const &_clust_orbit,
354  std::function<std::string(Index, Index)> method_namer,
355  std::map<UnitCellCoord, std::set<UnitCellCoord> > const &_nhood,
356  PrimNeighborList &_nlist,
357  std::vector<std::unique_ptr<FunctionVisitor> > const &visitors,
358  FunctionVisitor const &_site_func_labeler, std::string const &indent) {
359  std::stringstream bfunc_def_stream, bfunc_imp_stream;
360  bool make_newline = false;
361 
362  // loop over flowers (i.e., basis sites of prim)
363  for (auto const &nbor : _nhood) {
364  std::vector<std::string> formulae(_bset_orbit[0].size());
365 
366  Index nbor_ind = _nlist.neighbor_index(nbor.first);
367  Index sublat_ind = nbor.first.sublattice();
368 
369  // loop over site basis functions
370  BasisSet site_basis(_site_bases[sublat_ind]);
371  site_basis.set_dof_IDs(std::vector<Index>(1, nbor_ind));
372 
373  site_basis.accept(_site_func_labeler);
374  for (Index nsbf = 0; nsbf < site_basis.size(); nsbf++) {
375  Function const *func_ptr = site_basis[nsbf];
376 
377  auto get_quotient_bset = [func_ptr](BasisSet const &bset) -> BasisSet {
378  return bset.poly_quotient_set(func_ptr);
379  };
380 
381  std::vector<std::string> tformulae = flower_function_cpp_strings(
382  _bset_orbit, get_quotient_bset, _clust_orbit, _nhood, _nlist,
383  visitors, nbor.first);
384 
385  for (Index nf = 0; nf < tformulae.size(); nf++) {
386  if (!tformulae[nf].size()) continue;
387 
388  if (formulae[nf].size()) formulae[nf] += " + ";
389 
390  formulae[nf] += site_basis[nsbf]->formula();
391 
392  if (tformulae[nf] == "1" || tformulae[nf] == "(1)") continue;
393 
394  formulae[nf] += " * ";
395  formulae[nf] += tformulae[nf];
396  // formulae[nf] += ")";
397  }
398  }
399 
400  std::string method_name;
401  make_newline = false;
402  for (Index nf = 0; nf < formulae.size(); nf++) {
403  if (!formulae[nf].size()) {
404  continue;
405  }
406  make_newline = true;
407 
408  method_name = method_namer(nbor_ind, nf);
409 
410  bfunc_def_stream << indent << " template<typename Scalar>\n"
411  << indent << " Scalar " << method_name
412  << "(int occ_i, int occ_f) const;\n";
413 
414  bfunc_imp_stream << indent << " template<typename Scalar>\n"
415  << indent << "Scalar " << class_name
416  << "::" << method_name
417  << "(int occ_i, int occ_f) const {\n"
418  << indent << " return " << formulae[nf] << ";\n"
419  << indent << "}\n";
420  }
421  if (make_newline) {
422  bfunc_imp_stream << '\n';
423  bfunc_def_stream << '\n';
424  }
425  make_newline = false;
426  // \End Configuration specific part
427  } //\End loop over flowers
428  return std::tuple<std::string, std::string>(bfunc_def_stream.str(),
429  bfunc_imp_stream.str());
430 }
431 
432 //*******************************************************************************************
433 
434 // Divide by multiplicity. Same result as evaluating correlations via orbitree.
435 template <typename OrbitType>
436 std::vector<std::string> orbit_function_cpp_strings(
437  ClexBasis::BSetOrbit _bset_orbit, // used as temporary
438  OrbitType const &_clust_orbit, PrimNeighborList &_nlist,
439  std::vector<std::unique_ptr<FunctionVisitor> > const &visitors) {
440  std::string prefix, suffix;
441  std::vector<std::string> formulae(_bset_orbit[0].size(), std::string());
442  if (_clust_orbit.size() > 1) {
443  prefix = "(";
444  suffix = ") / " + std::to_string(_clust_orbit.size()) + ".";
445  }
446 
447  for (Index ne = 0; ne < _bset_orbit.size(); ne++) {
448  std::vector<PrimNeighborList::Scalar> nbor_IDs = _nlist.neighbor_indices(
449  _clust_orbit[ne].elements().begin(), _clust_orbit[ne].elements().end());
450  _bset_orbit[ne].set_dof_IDs(
451  std::vector<Index>(nbor_IDs.begin(), nbor_IDs.end()));
452  for (Index nl = 0; nl < visitors.size(); nl++)
453  _bset_orbit[ne].accept(*visitors[nl]);
454  }
455 
456  for (Index nf = 0; nf < _bset_orbit[0].size(); nf++) {
457  for (Index ne = 0; ne < _bset_orbit.size(); ne++) {
458  if (!_bset_orbit[ne][nf] || (_bset_orbit[ne][nf]->is_zero())) continue;
459 
460  if (formulae[nf].empty())
461  formulae[nf] += prefix;
462  else if ((_bset_orbit[ne][nf]->formula())[0] != '-' &&
463  (_bset_orbit[ne][nf]->formula())[0] != '+')
464  formulae[nf] += " + ";
465 
466  formulae[nf] += _bset_orbit[ne][nf]->formula();
467  }
468 
469  if (!formulae[nf].empty()) formulae[nf] += suffix;
470  }
471  return formulae;
472 }
473 
474 //*******************************************************************************************
476 template <typename OrbitType>
477 std::vector<std::string> flower_function_cpp_strings(
478  ClexBasis::BSetOrbit _bset_orbit, // used as temporary
479  std::function<BasisSet(BasisSet const &)> _bset_transform,
480  OrbitType const &_clust_orbit,
481  std::map<UnitCellCoord, std::set<UnitCellCoord> > const &_nhood,
482  PrimNeighborList &_nlist,
483  std::vector<std::unique_ptr<FunctionVisitor> > const &visitors,
484  UnitCellCoord const &nbor) {
485  std::vector<std::string> formulae;
486 
487  std::string prefix, suffix;
488 
489  std::set<UnitCellCoord> trans_set;
490 
491  // Find ucc's that might be translationally equivalent to current neighbor
492  for (IntegralCluster const &equiv : _clust_orbit) {
493  for (UnitCellCoord const &site : equiv.elements()) {
494  if (site.sublattice() == nbor.sublattice()) {
495  trans_set.insert(site);
496  }
497  }
498  }
499 
500  std::set<UnitCellCoord> equiv_ucc = ClexBasisWriter_impl::equiv_ucc(
501  trans_set.begin(), trans_set.end(), nbor, _clust_orbit.prototype().prim(),
502  _clust_orbit.sym_compare());
503 
504  // normalize by multiplicity (by convention)
505  if (_clust_orbit.size() > 1) {
506  prefix = "(";
507  suffix = ") / " + std::to_string(_clust_orbit.size()) + ".";
508  }
509 
510  // loop over equivalent clusters
511  for (Index ne = 0; ne < _clust_orbit.size(); ne++) {
512  if (formulae.empty()) formulae.resize(_bset_orbit[ne].size());
513 
516  for (UnitCellCoord const &trans : equiv_ucc) {
517  if (!contains(_clust_orbit[ne].elements(), trans)) continue;
518 
519  typename OrbitType::Element trans_clust =
520  _clust_orbit[ne] - (trans.unitcell() - nbor.unitcell());
521 
522  std::vector<PrimNeighborList::Scalar> nbor_IDs = _nlist.neighbor_indices(
523  trans_clust.elements().begin(), trans_clust.elements().end());
524 
525  _bset_orbit[ne].set_dof_IDs(
526  std::vector<Index>(nbor_IDs.begin(), nbor_IDs.end()));
527 
528  BasisSet transformed_bset(_bset_transform(_bset_orbit[ne]));
529  for (Index nl = 0; nl < visitors.size(); nl++)
530  transformed_bset.accept(*visitors[nl]);
531 
532  for (Index nf = 0; nf < transformed_bset.size(); nf++) {
533  if (!transformed_bset[nf] || (transformed_bset[nf]->is_zero()))
534  continue;
535 
536  if (formulae[nf].empty())
537  formulae[nf] += prefix;
538  else if ((transformed_bset[nf]->formula())[0] != '-' &&
539  (transformed_bset[nf]->formula())[0] != '+')
540  formulae[nf] += " + ";
541 
542  formulae[nf] += transformed_bset[nf]->formula();
543  }
544  }
545  }
546 
547  for (Index nf = 0; nf < formulae.size(); nf++) {
548  if (!formulae[nf].empty()) formulae[nf] += suffix;
549  }
550 
551  return formulae;
552 }
553 
554 //*******************************************************************************************
555 template <typename OrbitType>
556 void print_proto_clust_funcs(ClexBasis const &clex, std::ostream &out,
557  std::vector<OrbitType> const &_tree) {
558  // Prints out all prototype clusters (CLUST file)
559 
560  out << "COORD_MODE = " << xtal::COORD_MODE::NAME() << std::endl << std::endl;
561 
562  auto const &site_bases(clex.site_bases());
563 
564  out.flags(std::ios::showpoint | std::ios::fixed | std::ios::left);
565  out.precision(5);
566  auto it = site_bases.begin(), end_it = site_bases.end();
567  for (; it != end_it; ++it) {
568  out << "Basis site definitions for DoF " << it->first << ".\n";
569 
570  for (Index nb = 0; nb < (it->second).size(); ++nb) {
571  out << " Basis site " << nb + 1 << ":\n"
572  << " ";
573  clex.prim().basis()[nb].print(out);
574  out << "\n";
575  out << DoFType::traits(it->first).site_basis_description(
576  (it->second)[nb], clex.prim().basis()[nb], nb);
577  }
578  }
579 
580  out << "\n\n";
581  Index nf = 0;
582  for (Index i = 0; i < _tree.size(); i++) {
583  if (i == 0 ||
584  _tree[i].prototype().size() != _tree[i - 1].prototype().size())
585  out << "** " << _tree[i].prototype().size() << "-site clusters ** \n"
586  << std::flush;
587 
588  out << " ** Orbit " << i + 1 << " of " << _tree.size() << " **"
589  << " Points: " << _tree[i].prototype().size()
590  << " Mult: " << _tree[i].size()
591  << " MinLength: " << _tree[i].prototype().min_length()
592  << " MaxLength: " << _tree[i].prototype().max_length() << '\n'
593  << std::flush;
594 
595  out << " "
596  << "Prototype"
597  << " of " << _tree[i].size() << " Equivalent Clusters in Orbit " << i
598  << '\n'
599  << std::flush;
600  print_clust_basis(out, clex.bset_orbit(i)[0], _tree[i].prototype(), nf, 8,
601  '\n');
602 
603  nf += clex.bset_orbit(i)[0].size();
604  out << "\n\n" << std::flush;
605 
606  if (_tree[i].prototype().size() != 0) out << '\n' << std::flush;
607  }
608 }
609 
610 //*******************************************************************************************
611 
612 // keys of result are guaranteed to be in canonical translation unit
613 template <typename OrbitIterType>
614 std::map<UnitCellCoord, std::set<UnitCellCoord> > dependency_neighborhood(
615  OrbitIterType begin, OrbitIterType end) {
616  std::map<UnitCellCoord, std::set<UnitCellCoord> > result;
617 
618  if (begin == end) return result;
619 
620  typedef IntegralCluster cluster_type;
621  typedef typename OrbitIterType::value_type orbit_type;
622 
623  UnitCellCoord const *ucc_ptr(nullptr);
624  OrbitIterType begin2 = begin;
625  for (; begin2 != end; ++begin2) {
626  auto const &orbit = *begin2;
627  for (auto const &equiv : orbit) {
628  for (UnitCellCoord const &ucc : equiv) {
629  ucc_ptr = &ucc;
630  break;
631  }
632  if (ucc_ptr) break;
633  }
634  if (ucc_ptr) break;
635  }
636  if (!ucc_ptr) return result;
637 
638  Structure const &prim(begin->prototype().prim());
639  SymGroup identity_group(prim.factor_group().begin(),
640  (prim.factor_group().begin()) + 1);
641  orbit_type empty_orbit(cluster_type(prim), identity_group,
642  begin->sym_compare());
643 
644  // Loop over each site in each cluster of each orbit
645  for (; begin != end; ++begin) {
646  auto const &orbit = *begin;
647  for (auto const &equiv : orbit) {
648  for (UnitCellCoord const &ucc : equiv) {
649  // create a test cluster from prototype
650  cluster_type test(empty_orbit.prototype());
651 
652  // add the new site
653  test.elements().push_back(ucc);
654  test = orbit.sym_compare().prepare(test);
655 
656  UnitCell trans = test.element(0).unitcell() - ucc.unitcell();
657  for (UnitCellCoord const &ucc2 : equiv) {
658  result[test.element(0)].insert(ucc2 + trans);
659  }
660  }
661  }
662  }
663  return result;
664 }
665 
666 //*******************************************************************************************
667 
668 template <typename UCCIterType, typename IntegralClusterSymCompareType>
669 std::set<UnitCellCoord> equiv_ucc(
670  UCCIterType begin, UCCIterType end, UnitCellCoord const &pivot,
671  Structure const &prim, IntegralClusterSymCompareType const &sym_compare) {
672  std::set<UnitCellCoord> result;
673 
674  typedef IntegralCluster cluster_type;
675  typedef Orbit<IntegralClusterSymCompareType> orbit_type;
676 
677  if (begin == end) return result;
678 
679  SymGroup identity_group(prim.factor_group().begin(),
680  (prim.factor_group().begin()) + 1);
681  orbit_type empty_orbit(cluster_type(prim), identity_group, sym_compare);
682 
683  cluster_type pclust(empty_orbit.prototype());
684  pclust.elements().push_back(pivot);
685  pclust = sym_compare.prepare(pclust);
686  // std::cout << "pclust elements: \n" << pclust.elements() << "\n\n";
687  // by looping over each site in the grid,
688  for (; begin != end; ++begin) {
689  // create a test cluster from prototype
690  cluster_type test(empty_orbit.prototype());
691 
692  // add the new site
693  test.elements().push_back(*begin);
694  // std::cout << "Before prepare: " << test.element(0) << std::endl;
695  test = sym_compare.prepare(test);
696  // std::cout << "After prepare: " << test.element(0) << std::endl <<
697  // std::endl; std::cout << "test elements: \n" << test.elements() << "\n";
698 
699  if (sym_compare.equal(test, pclust)) {
700  result.insert(*begin);
701  }
702  }
703 
704  return result;
705 }
706 
707 //*******************************************************************************************
708 
709 template <typename OrbitType>
711  std::string const &class_name, ClexBasis const &clex,
712  std::vector<OrbitType> const &_tree,
713  std::map<UnitCellCoord, std::set<UnitCellCoord> > const &_nhood,
714  PrimNeighborList &_nlist, ParamPackMixIn const &_param_pack_mix_in,
715  std::vector<std::string> const &orbit_method_names,
716  std::vector<std::vector<std::string> > const &flower_method_names,
717  std::vector<std::vector<std::string> > const &dflower_method_names,
718  std::string const &indent) {
719  Index N_corr = clex.n_functions();
720 
721  // Lower bound of branch entries
722  Index N_flower = _nhood.size();
723 
724  // Lower bound of maximum neighbor index
725  Index N_hood = 0;
726 
727  // Find exact value of N_flower and N_hood by increasing lower bounds
728  for (auto const &nbor : _nhood) {
729  N_flower = max(_nlist.neighbor_index(nbor.first) + 1, N_flower);
730  for (UnitCellCoord const &ucc : nbor.second) {
731  N_hood = max(_nlist.neighbor_index(ucc) + 1, N_hood);
732  }
733  }
734 
735  std::stringstream ss;
736  // Write constructor
737  ss << indent << class_name << "::" << class_name << "() :\n"
738  << indent << " Clexulator_impl::Base(" << N_hood << ", " << N_corr << ", "
739  << N_flower << ") {\n";
740 
741  for (auto const &dof : clex.site_bases()) {
743  clex.prim(), dof.second, indent + " ");
744 
745  std::vector<DoFType::ParamAllocation> allo =
746  DoFType::traits(dof.first).param_pack_allocation(clex.prim(),
747  dof.second);
748  if (allo.empty()) continue;
749 
750  for (const auto &el : allo) {
751  Index num_param = el.num_param;
752  if (!valid_index(num_param)) num_param = N_hood;
753  ss << indent << " m_" << el.param_name
754  << "_param_key = m_params.allocate(\"" << el.param_name << "\", "
755  << el.param_dim << ", " << num_param << ", "
756  << (el.independent ? "true" : "false") << ");\n";
757  }
758 
759  if (dof.first != "occ")
760  ss << indent << " _register_local_dof(\"" << dof.first << "\", m_"
761  << dof.first << "_var_param_key.index());\n\n";
762 
763  ss << "\n";
764  }
765 
766  for (auto const &dof : clex.global_bases()) {
768  clex.prim(), dof.second, indent + " ");
769 
770  std::vector<DoFType::ParamAllocation> allo =
771  DoFType::traits(dof.first).param_pack_allocation(clex.prim(),
772  dof.second);
773  if (allo.empty()) continue;
774 
775  for (const auto &el : allo) {
776  Index num_param = el.num_param;
777  if (!valid_index(num_param))
778  throw std::runtime_error(
779  "Global DoF " + dof.first +
780  " requested invalid ClexParamPack allocation\n");
781  ss << indent << " m_" << el.param_name
782  << "_param_key = m_params.allocate(\"" << el.param_name << "\", "
783  << el.param_dim << ", " << num_param << ", "
784  << (el.independent ? "true" : "false") << ");\n";
785  }
786 
787  ss << indent << " _register_global_dof(\"" << dof.first << "\", m_"
788  << dof.first << "_var_param_key.index());\n\n";
789 
790  ss << "\n";
791  }
792 
793  ss << indent
794  << " m_corr_param_key = m_params.allocate(\"corr\", corr_size(), 1, "
795  "false);\n\n";
796 
797  Index ispec = 0;
798  for (auto const &specialization :
799  _param_pack_mix_in.scalar_specializations()) {
800  for (Index nf = 0; nf < orbit_method_names.size(); nf++) {
801  ss << indent << " m_orbit_func_table_" << ispec << "[" << nf << "] = &"
802  << class_name << "::" << orbit_method_names[nf] << "<"
803  << specialization.second << ">;\n";
804  }
805  ss << "\n\n";
806 
807  for (Index nb = 0; nb < flower_method_names.size(); nb++) {
808  for (Index nf = 0; nf < flower_method_names[nb].size(); nf++) {
809  ss << indent << " m_flower_func_table_" << ispec << "[" << nb << "]["
810  << nf << "] = &" << class_name << "::" << flower_method_names[nb][nf]
811  << "<" << specialization.second << ">;\n";
812  }
813  ss << "\n\n";
814  }
815 
816  for (Index nb = 0; nb < dflower_method_names.size(); nb++) {
817  for (Index nf = 0; nf < dflower_method_names[nb].size(); nf++) {
818  ss << indent << " m_delta_func_table_" << ispec << "[" << nb << "]["
819  << nf << "] = &" << class_name
820  << "::" << dflower_method_names[nb][nf] << "<"
821  << specialization.second << ">;\n";
822  }
823  ss << "\n\n";
824  }
825  ++ispec;
826  }
827 
828  // Write weight matrix used for the neighbor list
830  ss << indent << " m_weight_matrix.row(0) << " << W(0, 0) << ", " << W(0, 1)
831  << ", " << W(0, 2) << ";\n";
832  ss << indent << " m_weight_matrix.row(1) << " << W(1, 0) << ", " << W(1, 1)
833  << ", " << W(1, 2) << ";\n";
834  ss << indent << " m_weight_matrix.row(2) << " << W(2, 0) << ", " << W(2, 1)
835  << ", " << W(2, 2) << ";\n\n";
836 
837  {
838  // Write neighborhood of UnitCellCoord
839  // expand the _nlist to contain 'global_orbitree' (all that is needed for
840  // now)
841  std::set<UnitCellCoord> nbors; // restricted scope
842  flower_neighborhood(_tree.begin(), _tree.end(),
843  std::inserter(nbors, nbors.begin()));
844 
845  std::set<UnitCell> ucnbors;
846  for (UnitCellCoord const &ucc : nbors) ucnbors.insert(ucc.unitcell());
847 
848  if (!ucnbors.empty()) {
849  ss << indent << " m_neighborhood = std::set<UnitCell> {\n";
850  auto it = ucnbors.begin();
851  while (it != ucnbors.end()) {
852  // ss << " " << _nlist.neighbor_index(*it);
853  ss << indent << " UnitCell(" << (*it)[0] << ", " << (*it)[1] << ", "
854  << (*it)[2] << ")";
855  ++it;
856  if (it != ucnbors.end()) {
857  ss << ",";
858  }
859  ss << "\n";
860  }
861  ss << indent << " };\n";
862  ss << "\n\n";
863  }
864  }
865  ss << indent << " m_orbit_neighborhood.resize(corr_size());\n";
866  Index lno = 0;
867  for (Index no = 0; no < clex.n_orbits(); ++no) {
868  std::set<UnitCellCoord> nbors;
869  flower_neighborhood(_tree[no], std::inserter(nbors, nbors.begin()));
870 
871  std::set<UnitCell> ucnbors;
872  for (UnitCellCoord const &ucc : nbors) ucnbors.insert(ucc.unitcell());
873 
874  Index proto_index = lno;
875 
876  // If a flower has no associated basis functions, it will be left out.
877  // Doing otherwise would result in a mismatch between indexing of
878  // m_orbit_neighborhood and every other basis function indexing convention
879  if (clex.bset_orbit(no).size() == 0 || clex.bset_orbit(no)[0].size() == 0) {
880  continue;
881  }
882 
883  if (ucnbors.empty()) {
884  for (Index nf = 0; nf < clex.bset_orbit(no)[0].size(); ++nf) ++lno;
885  continue;
886  }
887 
888  ss << indent << " m_orbit_neighborhood[" << lno
889  << "] = std::set<UnitCell> {\n";
890 
891  auto it = ucnbors.begin();
892  while (it != ucnbors.end()) {
893  ss << indent << " UnitCell(" << (*it)[0] << ", " << (*it)[1] << ", "
894  << (*it)[2] << ")";
895  ++it;
896  if (it != ucnbors.end()) {
897  ss << ",";
898  }
899  ss << "\n";
900  }
901  ss << indent << " };\n";
902  ++lno;
903  for (Index nf = 1; nf < clex.bset_orbit(no)[0].size(); ++nf, ++lno) {
904  ss << indent << " m_orbit_neighborhood[" << lno
905  << "] = m_orbit_neighborhood[" << proto_index << "];\n";
906  }
907  ss << "\n";
908  }
909 
910  ss << indent << "}\n\n";
911 
912  return ss.str();
913 }
914 
915 template <typename OrbitType>
917  std::string const &class_name, ClexBasis const &clex,
918  std::vector<OrbitType> const &_tree,
919  std::vector<std::unique_ptr<OrbitFunctionTraits> > const
920  &_orbit_func_traits,
921  std::map<UnitCellCoord, std::set<UnitCellCoord> > const &_nhood,
922  PrimNeighborList &_nlist, std::string const &indent) {
923  std::string result(indent + "template<typename Scalar>\n" + indent + "void " +
924  class_name + "::_point_prepare(int nlist_ind) const {\n");
925 
926  // Use known clexbasis dependencies to construct point_prepare routine
927  for (auto const &doftype : clex.site_bases()) {
928  result +=
929  DoFType::traits(doftype.first)
930  .clexulator_point_prepare_string(clex.prim(), _nhood, _nlist,
931  doftype.second, indent + " ");
932  }
933  for (auto const &doftype : clex.global_bases()) {
934  result +=
935  DoFType::traits(doftype.first)
936  .clexulator_point_prepare_string(clex.prim(), _nhood, _nlist,
937  doftype.second, indent + " ");
938  }
939 
940  for (auto const &func_trait : _orbit_func_traits) {
941  result += func_trait->clexulator_point_prepare_string(
942  clex.prim(), _nhood, _nlist, indent + " ");
943  }
944  result += (indent + "}\n");
945  return result;
946 }
947 
948 template <typename OrbitType>
950  std::string const &class_name, ClexBasis const &clex,
951  std::vector<OrbitType> const &_tree,
952  std::vector<std::unique_ptr<OrbitFunctionTraits> > const
953  &_orbit_func_traits,
954  std::map<UnitCellCoord, std::set<UnitCellCoord> > const &_nhood,
955  PrimNeighborList &_nlist, std::string const &indent) {
956  std::string result(indent + "template<typename Scalar>\n" + indent + "void " +
957  class_name + "::_global_prepare() const {\n");
958 
959  // Use known clexbasis dependencies to construct point_prepare routine
960  for (auto const &doftype : clex.site_bases()) {
961  result += DoFType::traits(doftype.first)
963  clex.prim(), _nhood, _nlist, doftype.second, indent + "");
964  }
965 
966  // Use known clexbasis dependencies to construct point_prepare routine
967  for (auto const &doftype : clex.global_bases()) {
968  result += DoFType::traits(doftype.first)
970  clex.prim(), _nhood, _nlist, doftype.second, indent + "");
971  }
972 
973  for (auto const &func_trait : _orbit_func_traits) {
974  result += func_trait->clexulator_global_prepare_string(clex.prim(), _nhood,
975  _nlist, indent + "");
976  }
977 
978  result += (indent + "}\n");
979  return result;
980 }
981 
982 } // namespace ClexBasisWriter_impl
983 } // namespace CASM
984 
985 #endif
Index size() const
Definition: Array.hh:131
void set_dof_IDs(const std::vector< Index > &new_IDs)
Definition: BasisSet.cc:344
bool accept(const FunctionVisitor &visitor)
Definition: BasisSet.cc:234
Index n_orbits() const
Total number of BasisSet orbits.
Definition: ClexBasis.cc:93
std::map< DoFKey, std::vector< BasisSet > > const & site_bases() const
Const access to dictionary of all site BasisSets.
Definition: ClexBasis.hh:95
std::vector< BasisSet > BSetOrbit
Definition: ClexBasis.hh:33
ParsingDictionary< DoFType::Traits > const * dof_dict() const
Definition: ClexBasis.cc:79
std::map< DoFKey, std::vector< BasisSet > > const & global_bases() const
Const access to dictionary of all global BasisSets.
Definition: ClexBasis.hh:100
PrimType const & prim() const
Definition: ClexBasis.cc:71
Index n_functions() const
Total number of basis functions.
Definition: ClexBasis.cc:96
ClexBasisSpecs const & basis_set_specs() const
Definition: ClexBasis.cc:75
BSetOrbit const & bset_orbit(Index orbit_ind) const
Const access of BSetOrbit of orbit.
Definition: ClexBasis.hh:78
notstd::cloneable_ptr< ParamPackMixIn > m_param_pack_mix_in
std::vector< std::unique_ptr< FunctionVisitor > > const & _clust_function_visitors() const
void print_clexulator(std::string class_name, ClexBasis const &clex, std::vector< OrbitType > const &_tree, PrimNeighborList &_nlist, std::ostream &stream, double xtal_tol)
Print clexulator.
void print_param_pack(std::string class_name, ClexBasis const &clex, std::vector< OrbitType > const &_tree, PrimNeighborList &_nlist, std::ostream &stream, std::string const &_indent) const
Print ClexParamPack specialization.
std::vector< std::unique_ptr< OrbitFunctionTraits > > const & _orbit_func_traits() const
virtual std::string clexulator_global_prepare_string(Structure const &_prim, std::map< UnitCellCoord, std::set< UnitCellCoord > > const &_nhood, PrimNeighborList &_nlist, std::vector< BasisSet > const &site_bases, std::string const &indent) const
Definition: DoFTraits.cc:200
virtual std::string clexulator_point_prepare_string(Structure const &_prim, std::map< UnitCellCoord, std::set< UnitCellCoord > > const &_nhood, PrimNeighborList &_nlist, std::vector< BasisSet > const &site_bases, std::string const &indent) const
Definition: DoFTraits.cc:118
virtual std::string site_basis_description(BasisSet site_bset, Site site, Index site_ix) const
Definition: DoFTraits.cc:517
virtual std::vector< ParamAllocation > param_pack_allocation(Structure const &_prim, std::vector< BasisSet > const &_bases) const
Definition: DoFTraits.cc:443
virtual std::string clexulator_constructor_string(Structure const &_prim, std::vector< BasisSet > const &site_bases, std::string const &indent) const
Definition: DoFTraits.cc:479
Definition: Log.hh:48
An Orbit of Element.
Definition: Orbit.hh:43
ParamPackMixIn is interface class to control ClexParamPack portion of Clexulator printing Used primar...
std::map< std::string, std::string > const & scalar_specializations() const
Dictionary of pairs ("EvalMode", "ScalarType") These correspond to the underlying scalar type to be u...
The PrimNeighborList gives the coordinates of UnitCell that are neighbors of the origin UnitCell.
Definition: NeighborList.hh:39
std::vector< Scalar > neighbor_indices(UnitCellCoordIterator _begin, UnitCellCoordIterator _end)
Get neighborlist indices of a collection of UnitCells, stored in.
Scalar neighbor_index(UnitCellCoord const &_ucc)
Get neighborlist index of UnitCellCoord.
Matrix3Type weight_matrix() const
Return the weighting matrix W used to define the canonical order.
Definition: NeighborList.cc:13
Eigen::Matrix3l Matrix3Type
Definition: NeighborList.hh:44
Structure specifies the lattice and atomic basis of a crystal.
Definition: Structure.hh:30
const std::vector< xtal::Site > & basis() const
Definition: Structure.hh:102
const MasterSymGroup & factor_group() const
Definition: Structure.cc:107
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
Definition: SymGroup.hh:42
static std::string NAME()
get a string with the name of the active mode
Unit Cell Coordinates.
const UnitCell & unitcell() const
Unit Cell Indices.
std::string to_string(ENUM val)
Return string representation of enum class.
Definition: io_traits.hh:172
OutputIterator flower_neighborhood(OrbitType const &orbit, OutputIterator result)
Iterate over all sites in an orbit and insert a UnitCellCoord.
std::tuple< std::string, std::string > clexulator_dflower_function_strings(std::string const &class_name, ClexBasis::BSetOrbit const &_bset_orbit, ClexBasis::BSetOrbit const &_site_bases, OrbitType const &_clust_orbit, std::function< std::string(Index, Index)> method_namer, std::map< UnitCellCoord, std::set< UnitCellCoord > > const &_nhood, PrimNeighborList &_nlist, std::vector< std::unique_ptr< FunctionVisitor > > const &visitors, FunctionVisitor const &prefactor_labeler, std::string const &indent)
void print_proto_clust_funcs(ClexBasis const &clex, std::ostream &out, std::vector< OrbitType > const &_tree)
std::string clexulator_constructor_definition(std::string const &class_name, ClexBasis const &clex, std::vector< OrbitType > const &_tree, std::map< UnitCellCoord, std::set< UnitCellCoord > > const &_nhood, PrimNeighborList &_nlist, ParamPackMixIn const &_param_pack_mix_in, std::vector< std::string > const &orbit_method_names, std::vector< std::vector< std::string > > const &flower_method_names, std::vector< std::vector< std::string > > const &dflower_method_names, std::string const &indent)
std::string clexulator_point_prepare_definition(std::string const &class_name, ClexBasis const &clex, std::vector< OrbitType > const &_tree, std::vector< std::unique_ptr< OrbitFunctionTraits > > const &orbit_func_traits, std::map< UnitCellCoord, std::set< UnitCellCoord > > const &_nhood, PrimNeighborList &_nlist, std::string const &indent)
std::set< UnitCellCoord > equiv_ucc(UCCIterType begin, UCCIterType end, UnitCellCoord const &_pivot, Structure const &_prim, IntegralClusterSymCompareType const &_sym_compare)
std::vector< std::string > flower_function_cpp_strings(ClexBasis::BSetOrbit _bset_orbit, std::function< BasisSet(BasisSet const &)> _bset_transform, OrbitType const &_clust_orbit, std::map< UnitCellCoord, std::set< UnitCellCoord > > const &_nhood, PrimNeighborList &_nlist, std::vector< std::unique_ptr< FunctionVisitor > > const &_visitors, UnitCellCoord const &_nbor)
nlist_index is the index of the basis site in the neighbor list
std::tuple< std::string, std::string > clexulator_flower_function_strings(std::string const &class_name, ClexBasis::BSetOrbit const &_bset_orbit, OrbitType const &_clust_orbit, std::function< std::string(Index, Index)> method_namer, std::map< UnitCellCoord, std::set< UnitCellCoord > > const &_nhood, PrimNeighborList &_nlist, std::vector< std::unique_ptr< FunctionVisitor > > const &visitor, std::string const &indent)
Print the flower function formulae for orbit.
std::map< UnitCellCoord, std::set< UnitCellCoord > > dependency_neighborhood(OrbitIterType begin, OrbitIterType end)
std::string clexulator_interface_declaration(std::string const &class_name, ClexBasis const &clex, ParamPackMixIn const &_param_pack_mix_in, std::string const &indent)
std::string clexulator_private_method_declarations(std::string const &class_name, ClexBasis const &clex, std::string const &indent)
std::string clexulator_member_declarations(std::string const &class_name, ClexBasis const &clex, ParamPackMixIn const &_param_pack_mix_in, std::vector< std::unique_ptr< OrbitFunctionTraits > > const &orbit_func_traits, Index N_flower, std::string const &indent)
std::tuple< std::string, std::string > clexulator_orbit_function_strings(std::string const &class_name, ClexBasis::BSetOrbit const &_bset_orbit, OrbitType const &_clust_orbit, std::function< std::string(Index, Index)> method_namer, PrimNeighborList &_nlist, std::vector< std::unique_ptr< FunctionVisitor > > const &visitors, std::string const &indent)
std::string clexulator_public_method_declarations(std::string const &class_name, ClexBasis const &clex, std::string const &indent)
std::vector< std::string > orbit_function_cpp_strings(ClexBasis::BSetOrbit _bset_orbit, OrbitType const &_clust_orbit, PrimNeighborList &_nlist, std::vector< std::unique_ptr< FunctionVisitor > > const &visitors)
std::string clexulator_global_prepare_definition(std::string const &class_name, ClexBasis const &clex, std::vector< OrbitType > const &_tree, std::vector< std::unique_ptr< OrbitFunctionTraits > > const &orbit_func_traits, std::map< UnitCellCoord, std::set< UnitCellCoord > > const &_nhood, PrimNeighborList &_nlist, std::string const &indent)
Traits const & traits(std::string const &dof_key)
Lookup DoFType::Traits in the global dictionary.
Definition: DoFTraits.cc:46
Main CASM namespace.
Definition: APICommand.hh:8
jsonParser & to_json(const ClexDescription &desc, jsonParser &json)
void write_prim(const xtal::BasicStructure &prim, fs::path filename, COORD_TYPE mode, bool include_va=false)
Write prim.json to file.
const COORD_TYPE FRAC
Definition: enum.hh:8
Index print_clust_basis(std::ostream &stream, BasisSet _clust_basis, IntegralCluster const &_prototype, Index func_ind=0, int space=18, char delim='\n')
Definition: ClexBasis.cc:44
bool contains(const Container &container, const T &value)
Equivalent to container.end() != std::find(container.begin(), container.end(), value)
Definition: algorithm.hh:83
bool valid_index(Index i)
Definition: definitions.cc:5
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
PrototypePrinter< IntegralCluster > ProtoSitesPrinter
T max(const T &A, const T &B)
Definition: CASM_math.hh:95
pair_type bset
Definition: settings.cc:145
Unary transformation that behaves as Identity (i.e. transform(arg) == arg is true)
Definition: CASM_TMP.hh:85