25 double pretty(
double value,
double tol) {
26 double pretty_value = value;
27 if (std::abs(value) < tol) {
30 if (std::abs(
std::round(value) - value) < tol) {
42 return std::vector<double>(occupant_dof_size, 1. /
double(occupant_dof_size));
46 std::vector<double> tprob(occupant_dof_size, 0.);
53 const std::vector<std::string> &allowed_occupants) {
55 if (sublat_comp.indices.find(sublat_index) != sublat_comp.indices.end()) {
56 std::vector<double> tprob(allowed_occupants.size(), 0.);
58 for (
Index ns = 0; ns < allowed_occupants.size(); ns++) {
59 auto it = sublat_comp.values.find(allowed_occupants[ns]);
60 if (it == sublat_comp.values.end()) {
61 throw std::runtime_error(
62 "BasisFunctionSpecs error: basis site " +
64 " must have a composition specified for species " +
65 allowed_occupants[ns] +
"\n");
67 tprob[ns] = it->second;
70 for (
Index j = 0; j < tprob.size(); j++) {
76 throw std::runtime_error(
77 "BasisFunctionSpecs error: compositions are not specified for basis "
82 namespace OccupationDoFSpecs_impl {
102 : occ_specs(_occ_specs) {
109 for (
const auto &vec : tmp) {
111 std::set<std::string>{vec.begin(), vec.end()});
124 error.insert(
"No composition is given for '" +
name +
" on sublattice " +
131 for (
const auto &pair : sublat_comp.
values) {
132 if (
std::find(begin, end, pair.first) == end) {
133 error.insert(
to_string(pair.first) +
" is not allowed on sublattice " +
142 for (
const auto &b : sublat_comp.indices) {
145 " is out of range.");
153 std::set<Index> found;
155 for (
const auto &b : sublat_comp.indices) {
158 " is out of range.");
160 if (found.count(b)) {
183 std::vector<double> tprob;
197 throw std::runtime_error(
198 "BasisFunctionSpecs error: unknown SITE_BASIS_FUNCTION_TYPE");
219 std::vector<double> tprob =
222 if (tprob.size() != allowed_occs.
size()) {
223 std::stringstream ss;
224 ss <<
"Error in OccupationDoFTraits::construct_site_bases: occ_probs "
226 ss <<
" sublattice_index=" << sublattice_index <<
" ";
227 ss <<
" occ_probs=[";
228 for (
Index i = 0; i < tprob.size(); ++i) {
229 if (i != 0) ss <<
",";
233 throw std::runtime_error(ss.str());
237 auto eq_map_range = orbit.equivalence_map(0);
238 SymGroup invariant_group{eq_map_range.first, eq_map_range.second};
242 allowed_occs, tprob, sublattice_index, invariant_group);
254 std::vector<BasisSet> site_bases{_prim.
basis().size()};
257 auto const &occ_specs =
258 get<OccupationDoFSpecs>(this->
name(), _basis_function_specs);
261 for (
auto const &orbit : _asym_unit) {
262 UnitCellCoord const &prototype_uccoord = orbit.prototype()[0];
271 auto &prototype_site_basis = site_bases[prototype_sublattice_index];
279 for (
Index ne = 1; ne < orbit.size(); ne++) {
280 Index other_sublattice_index = orbit[ne][0].sublattice();
281 auto &other_site_basis = site_bases[other_sublattice_index];
282 other_site_basis = prototype_site_basis;
283 other_site_basis.apply_sym(orbit.equivalence_map()[ne][0]);
285 other_site_basis.set_dof_IDs({other_sublattice_index});
294 std::map<
UnitCellCoord, std::set<UnitCellCoord>>
const &_nhood,
296 std::string
const &indent)
const {
297 std::stringstream ss;
298 ss << indent <<
"switch(nlist_ind) {\n";
299 for (
auto const &nbor : _nhood) {
300 ss << indent <<
"case " << _nlist.
neighbor_index(nbor.first) <<
":\n";
301 std::stringstream ssfunc;
303 std::map<Index, std::set<Index>> sublat_nhood;
304 for (
auto const &ucc : nbor.second) {
305 sublat_nhood[ucc.sublattice()].insert(_nlist.
neighbor_index(ucc));
308 for (
auto const &sublat : sublat_nhood) {
309 Index b = sublat.first;
310 for (
Index n : sublat.second) {
311 for (
Index f = 0; f < site_bases[b].size(); f++) {
312 ssfunc << indent <<
" ParamPack::Val<Scalar>::set(m_params, m_"
314 <<
", eval_occ_func_" << b <<
"_" << f <<
"(" << n <<
"));\n";
318 if (ssfunc.str().size()) {
320 <<
"_param_key) != ParamPack::READ) {\n"
321 << ssfunc.str() << indent <<
" }\n";
323 ss << indent <<
" break;\n";
325 ss << indent <<
"}\n";
333 std::map<
UnitCellCoord, std::set<UnitCellCoord>>
const &_nhood,
335 std::string
const &indent)
const {
336 std::stringstream ss, ssfunc;
337 std::map<Index, std::set<Index>> tot_nhood;
338 for (
auto const &nbor : _nhood)
339 for (
auto const &ucc : nbor.second)
342 for (
auto const &nbor : tot_nhood) {
343 Index b = nbor.first;
344 for (
Index n : nbor.second) {
345 for (
Index f = 0; f < site_bases[b].size(); f++) {
346 ssfunc << indent <<
" ParamPack::Val<Scalar>::set(m_params, m_"
348 <<
", eval_occ_func_" << b <<
"_" << f <<
"(" << n <<
"));\n";
352 if (ssfunc.str().size()) {
354 <<
"_param_key) != ParamPack::READ) {\n"
355 << ssfunc.str() << indent <<
"}\n";
363 Structure const &_prim, std::vector<BasisSet>
const &_site_bases,
364 std::string
const &indent)
const {
365 std::stringstream stream;
366 std::vector<Orbit<PrimPeriodicSymCompare<IntegralCluster>>> asym_unit;
367 std::ostream nullstream(0);
377 std::shared_ptr<const Structure>(&_prim, [](
const Structure *) {});
378 make_prim_periodic_asymmetric_unit(_prim_ptr,
380 std::back_inserter(asym_unit), nullstream);
382 for (
Index no = 0; no < asym_unit.size(); no++) {
383 Index nb = asym_unit[no][0][0].sublattice();
384 if (_site_bases[nb].size() == 0)
continue;
387 <<
"// Occupation Function tables for basis sites in asymmetric unit "
389 for (
Index ne = 0; ne < asym_unit[no].size(); ne++) {
390 nb = asym_unit[no][ne][0].sublattice();
391 stream << indent <<
"// - basis site " << nb <<
":\n";
392 for (
Index f = 0; f < _site_bases[nb].size(); f++) {
393 stream << indent <<
"double "
394 <<
"m_occ_func_" << nb <<
'_' << f <<
'['
395 << _prim.
basis()[nb].occupant_dof().size() <<
"];\n";
406 Structure const &_prim, std::vector<BasisSet>
const &_site_bases,
407 const std::string &indent)
const {
408 std::stringstream stream;
409 std::vector<Orbit<PrimPeriodicSymCompare<IntegralCluster>>> asym_unit;
410 std::ostream nullstream(0);
420 std::shared_ptr<const Structure>(&_prim, [](
const Structure *) {});
421 make_prim_periodic_asymmetric_unit(_prim_ptr,
423 std::back_inserter(asym_unit), nullstream);
425 for (
Index no = 0; no < asym_unit.size(); no++) {
426 Index nb = asym_unit[no][0][0].sublattice();
427 if (_site_bases[nb].size() == 0)
continue;
429 for (
Index ne = 0; ne < asym_unit[no].size(); ne++) {
430 nb = asym_unit[no][ne][0].sublattice();
434 <<
"// Occupation Function evaluators and accessors for basis site "
436 for (
Index f = 0; f < _site_bases[nb].size(); f++) {
437 stream << indent <<
"double const &eval_occ_func_" << nb <<
'_' << f
438 <<
"(const int &nlist_ind) const {\n"
439 << indent <<
" return "
440 <<
"m_occ_func_" << nb <<
'_' << f
441 <<
"[_configdof().occ(_l(nlist_ind))];\n"
445 indent <<
"double const &occ_func_" << nb <<
'_' << f
446 <<
"(const int &nlist_ind) const {\n"
447 << indent <<
" return "
460 std::vector<DoFType::ParamAllocation>
462 Structure const &_prim, std::vector<BasisSet>
const &_bases)
const {
463 std::vector<DoFType::ParamAllocation> result;
465 for (
BasisSet const &basis : _bases) {
466 NB =
max(basis.size(), NB);
478 Structure const &_prim, std::vector<BasisSet>
const &_site_bases,
479 const std::string &indent)
const {
480 std::stringstream stream;
481 stream.flags(std::ios::showpoint | std::ios::fixed | std::ios::right);
482 stream.precision(10);
484 std::vector<Orbit<PrimPeriodicSymCompare<IntegralCluster>>> asym_unit;
485 std::ostream nullstream(0);
495 std::shared_ptr<const Structure>(&_prim, [](
const Structure *) {});
496 make_prim_periodic_asymmetric_unit(_prim_ptr,
498 std::back_inserter(asym_unit), nullstream);
500 for (
const auto &asym : asym_unit) {
501 for (
const auto &equiv : asym) {
502 Index nb = equiv[0].sublattice();
503 for (
Index f = 0; f < _site_bases[nb].size(); f++) {
504 for (
Index s = 0;
s < _prim.
basis()[nb].occupant_dof().size();
s++) {
506 _site_bases[nb][f]->accept(t_eval);
508 if (
s == 0) stream << indent;
509 stream <<
"m_occ_func_" << nb <<
'_' << f <<
'[' <<
s
510 <<
"] = " << t_eval.
value();
511 if (
s + 1 == _prim.
basis()[nb].occupant_dof().size())
524 Index site_ix)
const {
525 std::stringstream ss;
526 if (site_bset.
size() == 0) ss <<
" [No site basis functions]\n\n";
531 std::vector<DoF::RemoteHandle> handles{
536 for (
Index f = 0; f < site_bset.
size(); f++) {
538 if (
s == 0) ss <<
" ";
539 ss <<
" \\phi_{" << site_ix <<
"," << f <<
"}["
541 <<
"] = " <<
pretty(site_bset[f]->remote_eval(), 1e-10);
551 std::vector<std::unique_ptr<FunctionVisitor>>
553 std::string
const &nlist_specifier)
const {
554 std::vector<std::unique_ptr<FunctionVisitor>> result;
555 result.push_back(std::unique_ptr<FunctionVisitor>(
560 std::vector<std::unique_ptr<FunctionVisitor>>
562 std::vector<std::unique_ptr<FunctionVisitor>> result;
563 result.push_back(std::unique_ptr<FunctionVisitor>(
570 fs::path dof_specs_path{
"dof_specs"};
571 fs::path subpath = dof_specs_path / this->
name();
573 if (subparser->value) {
574 parser.
value->dof_specs.push_back(std::move(subparser->value));
582 get<OccupationDoFSpecs>(this->
name(), basis_function_specs);
598 return notstd::make_unique<DoF_impl::OccupationDoFSpecs>(
603 return notstd::make_unique<DoF_impl::OccupationDoFSpecs>(
608 std::vector<DoF_impl::SublatComp> sublat_composition) {
609 return notstd::make_unique<DoF_impl::OccupationDoFSpecs>(sublat_composition);
613 namespace parse_OccupationDoFSpecs_impl {
630 void from_json(std::vector<DoF_impl::SublatComp> &sublat_composition,
632 sublat_composition.clear();
633 for (
auto it = json.
begin(); it != json.
end(); ++it) {
634 std::set<Index> sublat_indices;
635 it->find(
"sublat_indices")->get(sublat_indices);
636 std::map<std::string, double> sublat_values;
637 it->find(
"composition")->get(sublat_values);
638 sublat_composition.emplace_back(sublat_indices, sublat_values);
642 void to_json(std::vector<DoF_impl::SublatComp>
const &sublat_composition,
645 for (
auto const &sublat_comp : sublat_composition) {
647 tjson[
"sublat_indices"] = sublat_comp.indices;
648 tjson[
"composition"] = sublat_comp.values;
659 auto it = parser.
self.
find(
"site_basis_functions");
661 parser.
error.insert(
"Error: Required 'site_basis_functions' not found.");
663 if (it->is_string()) {
666 parser.
value = notstd::make_unique<DoF_impl::OccupationDoFSpecs>(
667 site_basis_function_type);
668 }
else if (it->is_array()) {
670 std::vector<DoF_impl::SublatComp> sublat_composition;
672 parser.
value = notstd::make_unique<DoF_impl::OccupationDoFSpecs>(
674 }
catch (std::exception &e) {
676 "Error: 'site_basis_functions' is an array, but failed to read "
677 "sublattice compositions.");
681 "Error: 'site_basis_functions' is neither a string nor an array with "
682 "sublattice compositions.");
691 "site_basis_function_type";
694 std::vector<std::string>>
695 traits<DoF_impl::SITE_BASIS_FUNCTION_TYPE>::strval = {
697 {
"CHEBYCHEV",
"Chebychev",
"chebychev"}},
699 {
"OCCUPATION",
"Occupation",
"occupation"}},
701 {
"COMPOSITION",
"Composition",
"composition"}}};
720 json[
"site_basis_functions"] =
std::set< std::string > & s
#define ENUM_JSON_IO_DEF(ENUM)
#define ENUM_IO_DEF(ENUM)
void construct_orthonormal_discrete_functions(const DiscreteDoF &allowed_occs, const Eigen::MatrixXd &gram_mat, Index basis_ind, const SymGroup &symgroup)
int register_remotes(const std::vector< DoF::RemoteHandle > &remote_handles)
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 override
void parse_dof_specs(InputParser< BasisFunctionSpecs > &parser, Structure const &prim) const override
Parse DoF-specific basis function specs & validate.
void dof_specs_to_json(BasisFunctionSpecs const &basis_function_specs, jsonParser &json, Structure const &prim) const override
Output DoF-specific basis function specs to json.
DoFType::Traits * _clone() const override
std::string site_basis_description(BasisSet site_bset, Site site, Index site_ix) const override
std::string clexulator_member_declarations_string(Structure const &_prim, std::vector< BasisSet > const &site_bases, std::string const &indent) const override
std::vector< std::unique_ptr< FunctionVisitor > > site_function_visitors(std::string const &nlist_specifier) const override
std::vector< DoFType::ParamAllocation > param_pack_allocation(Structure const &_prim, std::vector< BasisSet > const &_bases) const override
std::string clexulator_private_method_declarations_string(Structure const &_prim, std::vector< BasisSet > const &site_bases, std::string const &indent) const override
std::string clexulator_constructor_string(Structure const &_prim, std::vector< BasisSet > const &site_bases, std::string const &indent) const override
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 override
std::vector< BasisSet > construct_site_bases(Structure const &_prim, std::vector< Orbit< PrimPeriodicSymCompare< IntegralCluster >>> &_asym_unit, BasisFunctionSpecs const &_basis_function_specs) const override
Construct the site basis (if DOF_MODE is LOCAL) for a DoF, given its site.
std::vector< std::unique_ptr< FunctionVisitor > > clust_function_visitors() const override
Collection of all the traits specific to a DoF type.
std::string site_basis_name() const
std::string const & name() const
Index size() const override
The PrimNeighborList gives the coordinates of UnitCell that are neighbors of the origin UnitCell.
Scalar neighbor_index(UnitCellCoord const &_ucc)
Get neighborlist index of UnitCellCoord.
Structure specifies the lattice and atomic basis of a crystal.
const std::vector< xtal::Site > & basis() const
std::vector< SymGroupRepID > occupant_symrep_IDs() const
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
iterator begin()
Returns const_iterator to beginning of JSON object or JSON array.
iterator end()
Returns iterator to end of JSON object or JSON array.
jsonParser & put_obj()
Puts new empty JSON object.
iterator find(const std::string &name)
Return iterator to JSON object value with 'name'.
jsonParser & put_array()
Puts new empty JSON array.
const std::vector< Molecule > & occupant_dof() const
std::vector< std::string > allowed_occupants() const
const Site & sublattice_site(const PrimType &prim) const
Get reference to corresponding sublattice site in the unit structure.
std::string to_string(ENUM val)
Return string representation of enum class.
Eigen::MatrixXd pretty(const Eigen::MatrixXd &M, double tol)
Round entries that are within tol of being integer to that integer value.
Eigen::CwiseUnaryOp< decltype(Local::round_l< typename Derived::Scalar >), const Derived > round(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd.
std::vector< std::vector< std::string > > allowed_molecule_names(BasicStructure const &_struc)
Returns a vector with a list of allowed molecule names at each site.
jsonParser & push_back(const T &value, Args &&... args)
GenericDatumFormatter< std::string, ConfigEnumDataType > name()
Validator validate(OccupationDoFSpecs const &occ_specs, const Structure &prim)
std::vector< double > chebychev_sublat_prob_vec(Index occupant_dof_size)
std::vector< double > _make_occ_probs(const Site &site, Index b_ind, OccupationDoFSpecs const &occ_specs)
std::vector< double > composition_sublat_prob_vec(const OccupationDoFSpecs &occ_specs, Index sublat_index, const std::vector< std::string > &allowed_occupants)
std::vector< double > occupation_sublat_prob_vec(Index occupant_dof_size)
void _construct_orthonormal_discrete_functions(BasisSet &site_basis, Orbit< PrimPeriodicSymCompare< IntegralCluster >> const &orbit, Structure const &prim, DoF_impl::OccupationDoFSpecs const &occ_specs)
std::unique_ptr< DoFSpecs > occupation_bfuncs()
DoF_impl::OccupationDoFTraits occupation()
std::unique_ptr< DoFSpecs > composition_bfuncs(std::vector< DoF_impl::SublatComp > sublat_composition)
std::unique_ptr< DoFSpecs > chebychev_bfuncs()
void to_json(std::vector< DoF_impl::SublatComp > const &sublat_composition, jsonParser &json)
void from_json(std::vector< DoF_impl::SublatComp > &sublat_composition, const jsonParser &json)
void _require_site_basis_functions(InputParser< DoF_impl::OccupationDoFSpecs > &parser, const Structure &prim)
jsonParser & to_json(const ClexDescription &desc, jsonParser &json)
GenericDatumFormatter< std::string, DataObject > name()
Iterator find(Iterator begin, Iterator end, const T &value, BinaryCompare q)
Equivalent to std::find(begin, end, value), but with custom comparison.
INDEX_TYPE Index
For long integer indexing:
void parse(InputParser< ConfigEnumOptions > &parser, std::string method_name, PrimClex const &primclex, DataFormatterDictionary< Configuration > const &dict)
T max(const T &A, const T &B)
Specify how to construct basis functions.
N-nary function that behaves as a constant (i.e. transform(arg1,arg2,...) == constant is true)
void check_sublat_indices()
OccupationDoFSpecs const & occ_specs
std::vector< std::set< std::string > > allowed_molecule_names
void check_molecule_names()
void check_sublat_molecule_names(Index b, DoF_impl::SublatComp const &sublat_comp, const std::set< std::string > &allowed_molecule_names)
OccupationDoFSpecsValidator(OccupationDoFSpecs const &_occ_specs, Structure const &prim)
std::string _name() const override
SITE_BASIS_FUNCTION_TYPE site_basis_function_type
std::vector< SublatComp > sublat_composition
std::map< std::string, double > values
Data structure to hold error and warning messages.
std::set< std::string > error