CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
bset.cc
Go to the documentation of this file.
1 #include <cstring>
6 #include "casm/app/AppIO.hh"
8 #include "casm/clex/PrimClex.hh"
11 
12 namespace CASM {
13 
14  namespace Completer {
15 
17 
20 
21  m_desc.add_options()
22  ("update,u", "Update basis set")
23  ("orbits", "Pretty-print orbit prototypes")
24  ("functions", "Pretty-print prototype cluster functions for each orbit")
25  ("clusters", "Pretty-print all clusters")
26  ("clex", po::value<std::string>(), "Name of the cluster expansion using the basis set")
27  ("force,f", "Force overwrite");
28  return;
29  }
30  }
31 
32  // ///////////////////////////////////////
33  // 'clusters' function for casm
34  // (add an 'if-else' statement in casm.cpp to call this)
35 
36  int bset_command(const CommandArgs &args) {
37 
38  po::variables_map vm;
39 
41  Completer::BsetOption bset_opt;
42 
43  try {
44  po::store(po::parse_command_line(args.argc, args.argv, bset_opt.desc()), vm); // can throw
45  bool call_help = false;
46 
49  if(vm.count("help") || call_help) {
50  args.log << "\n";
51  args.log << bset_opt.desc() << std::endl;
52 
53  return 0;
54  }
55 
56  if(vm.count("desc")) {
57  args.log << "\n";
58  args.log << bset_opt.desc() << std::endl;
59  args.log << "DESCRIPTION" << std::endl;
60  args.log << " Generate and inspect cluster basis functions. A bspecs.json file should be available at\n"
61  << " $ROOT/basis_set/$current_bset/bspecs.json\n"
62  << " Run 'casm format --bspecs' for an example file.\n\n" ;
63 
64  return 0;
65  }
66 
67  po::notify(vm); // throws on error, so do after help in case
68  // there are any problems
69  }
70  catch(po::error &e) {
71  args.err_log << bset_opt.desc() << std::endl;
72  args.err_log << "\nERROR: " << e.what() << std::endl << std::endl;
73  return ERR_INVALID_ARG;
74  }
75  catch(std::exception &e) {
76  args.err_log << bset_opt.desc() << std::endl;
77  args.err_log << "\nERROR: " << e.what() << std::endl;
78  return ERR_UNKNOWN;
79 
80  }
81 
82  const fs::path &root = args.root;
83  if(root.empty()) {
84  args.err_log.error("No casm project found");
85  args.err_log << std::endl;
86  return ERR_NO_PROJ;
87  }
88 
89  // If 'args.primclex', use that, else construct PrimClex in 'uniq_primclex'
90  // Then whichever exists, store reference in 'primclex'
91  std::unique_ptr<PrimClex> uniq_primclex;
92  PrimClex &primclex = make_primclex_if_not(args, uniq_primclex);
93  const DirectoryStructure &dir = primclex.dir();
94  const ProjectSettings &set = primclex.settings();
95  std::string bset;
96  ClexDescription clex_desc;
97 
98  if(!vm.count("clex")) {
99  clex_desc = set.default_clex();
100  }
101  else {
102  auto it = set.cluster_expansions().find(vm["clex"].as<std::string>());
103  if(it == set.cluster_expansions().end()) {
104  args.err_log.error("Invalid --clex value");
105  args.err_log << vm["clex"].as<std::string>() << " not found.";
106  return ERR_INVALID_ARG;
107  }
108  clex_desc = it->second;
109  }
110  bset = clex_desc.bset;
111 
112  if(vm.count("update")) {
113 
114  // initialize project info
115  Structure prim = primclex.get_prim();
116 
117  if(!fs::is_regular_file(dir.bspecs(bset))) {
118  args.err_log.error("'bspecs.json' file not found");
119  args.err_log << "expected basis set specifications file at: " << dir.bspecs(bset) << "\n" << std::endl;
120  return ERR_MISSING_INPUT_FILE;
121  }
122 
123 
124  std::vector<fs::path> filepaths({dir.clust(bset),
125  dir.basis(bset),
126  dir.clexulator_src(set.name(), bset),
127  dir.clexulator_o(set.name(), bset),
128  dir.clexulator_so(set.name(), bset)
129  });
130 
131  bool any_existing_files = false;
132  std::for_each(filepaths.cbegin(),
133  filepaths.cend(),
134  [&](const fs::path & p) {
135  if(fs::exists(p)) {
136  if(!any_existing_files) {
137  args.log.custom("Found existing files");
138  any_existing_files = true;
139  }
140  args.log << "found: " << p << "\n";
141  }
142  });
143 
144  if(any_existing_files) {
145  if(vm.count("force")) {
146  args.log << "Using --force. Will overwrite existing files.\n" << std::endl;
147  fs::remove(dir.clexulator_src(set.name(), bset));
148  fs::remove(dir.clexulator_o(set.name(), bset));
149  fs::remove(dir.clexulator_so(set.name(), bset));
150  if(args.primclex) {
151  args.primclex->refresh(false, false, false, false, true);
152  }
153  }
154  else {
155  args.log << "Exiting due to existing files. Use --force to force overwrite.\n" << std::endl;
156  return ERR_EXISTING_FILE;
157  }
158  }
159 
160  SiteOrbitree tree(prim.lattice(), primclex.crystallography_tol());
161 
162  try {
163  jsonParser bspecs_json(dir.bspecs(bset));
164 
165  args.log.generate("Cluster orbits");
166  args.log.begin_lap();
167  tree = make_orbitree(prim, bspecs_json, primclex.crystallography_tol());
168  if(tree.min_num_components < 2) {
169  args.err_log.error("Generating orbitree");
170  args.err_log << "Custom clusters include a site with only 1 allowed component. \n";
171  args.err_log << "This is not currently supported.\n" << std::endl;
172  for(int nb = 0; nb < tree.size(); ++nb) {
173  for(int no = 0; no < tree[nb].size(); ++no) {
174  for(int ns = 0; ns < tree[nb][no].prototype.size(); ++ns) {
175  if(tree[nb][no].prototype[ns].site_occupant().size() < 2) {
176  args.err_log << "--- Prototype --- " << std::endl;
177  tree[nb][no].prototype.print(args.err_log, '\n');
178  break;
179  }
180  }
181  }
182  }
183  return ERR_INVALID_INPUT_FILE;
184  }
185  tree.generate_clust_bases();
186  tree.get_index();
187  args.log << "orbit generation time: " << args.log.lap_time() << " (s)\n";
188  args.log << "# of cluster orbits: " << tree.Norbits << "\n";
189  args.log << "# of basis functions: " << tree.basis_set_size() << "\n" << std::endl;
190  }
191  catch(std::exception &e) {
192  args.err_log << e.what() << std::endl;
193  return ERR_INVALID_INPUT_FILE;
194  }
195 
196  // -- write clust.json ----------------
197  args.log.write("Cluster and basis set files");
198  jsonParser clust_json;
199  to_json(jsonHelper(tree, prim), clust_json).write(dir.clust(bset));
200 
201  args.log << "write: " << dir.clust(bset) << std::endl;
202 
203 
204  // -- write basis.json ----------------
205  jsonParser basis_json;
206  write_basis(tree, prim, basis_json, primclex.crystallography_tol());
207  basis_json.write(dir.basis(bset));
208 
209  args.log << "write: " << dir.basis(bset) << std::endl;
210 
211 
212  // -- write global Clexulator
213 
214  // get the neighbor list
215  PrimNeighborList nlist(
216  set.nlist_weight_matrix(),
217  set.nlist_sublat_indices().begin(),
218  set.nlist_sublat_indices().end()
219  );
220 
221  // expand the nlist to contain 'tree'
222  std::set<UnitCellCoord> nbors;
223  neighborhood(std::inserter(nbors, nbors.begin()), tree, prim, primclex.crystallography_tol());
224  nlist.expand(nbors.begin(), nbors.end());
225 
226  // write source code
227  fs::ofstream outfile;
228  outfile.open(dir.clexulator_src(set.name(), bset));
229  print_clexulator(prim, tree, nlist, set.clexulator(), outfile, primclex.crystallography_tol());
230  outfile.close();
231  args.log << "write: " << dir.clexulator_src(set.name(), bset) << "\n" << std::endl;
232 
233  // compile clexulator
234  primclex.clexulator(set.default_clex());
235  }
236  else if(vm.count("orbits") || vm.count("clusters") || vm.count("functions")) {
237 
238  if(!fs::exists(dir.clust(bset))) {
239  args.err_log.error("No 'clust.json' file found");
240  args.err_log << "Make sure to update your basis set with 'casm bset -u'.\n" << std::endl;
241  return ERR_MISSING_DEPENDS;
242  }
243 
244  primclex.orbitree(clex_desc);
245 
246  if(vm.count("orbits")) {
247  args.log.custom("Prototype clusters");
248  primclex.orbitree(clex_desc).print_proto_clust(args.log);
249  args.log << std::endl;
250  }
251  if(vm.count("clusters")) {
252  args.log.custom("All clusters");
253  primclex.orbitree(clex_desc).print_full_clust(args.log);
254  args.log << std::endl;
255  }
256  if(vm.count("functions")) {
257  args.log.custom("Basis functions");
258  primclex.orbitree(clex_desc).print_proto_clust_funcs(args.log);
259  args.log << std::endl;
260  }
261  }
262  else {
263  args.err_log.error("Unknown error");
264  args.err_log << bset_opt.desc() << "\n" << std::endl;
265  }
266 
267  return 0;
268  };
269 
270 }
271 
Data structure holding basic CASM command info.
Clexulator clexulator(const ClexDescription &key) const
Definition: PrimClex.cc:1030
Specifies a particular cluster expansion.
ClustJsonHelper< ValueType > jsonHelper(ValueType &_value, const Structure &_struc, double tol=TOL)
Definition: jsonClust.hh:62
#define ERR_UNKNOWN
Eigen::Matrix3l nlist_weight_matrix() const
Get neighbor list weight matrix.
#define ERR_INVALID_ARG
Specification of CASM project directory structure.
void write(const std::string &what)
Definition: Log.hh:66
const DirectoryStructure & dir() const
Definition: PrimClex.hh:112
void write(const std::string &file_name, unsigned int indent=2, unsigned int prec=12) const
Write json to file.
Definition: jsonParser.cc:191
Structure specifies the lattice and atomic basis of a crystal.
Definition: Structure.hh:29
jsonParser & to_json(const ClexDescription &desc, jsonParser &json)
PrimClex * primclex
Definition: settings.cc:101
void add_help_suboption()
Add a plain –help suboption.
Definition: Handlers.cc:276
void begin_lap()
Definition: Log.cc:28
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
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
const Lattice & lattice() const
double lap_time() const
Definition: Log.cc:32
ProjectSettings & set
Definition: settings.cc:103
void print_proto_clust_funcs(std::ostream &out) const
fs::path bspecs(std::string bset) const
Return basis function specs (bspecs.json) file path.
void custom(const std::string &what)
Definition: Log.hh:96
std::string name() const
Get project name.
void print_proto_clust(std::ostream &out) const
void generate(const std::string &what)
Definition: Log.hh:41
double crystallography_tol() const
Definition: PrimClex.hh:124
const po::options_description & desc()
Get the program options, filled with the initialized values.
Definition: Handlers.cc:160
Read/modify settings of an already existing CASM project.
fs::path clexulator_so(std::string project, std::string bset) const
Returns path to global clexulator so file.
fs::path clust(std::string bset) const
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
fs::path clexulator_src(std::string project, std::string bset) const
Returns path to global clexulator source file.
int bset_command(const CommandArgs &args)
Definition: bset.cc:36
fs::path basis(std::string bset) const
po::options_description m_desc
Boost program options. All the derived classes have them, but will fill them up themselves.
Definition: Handlers.hh:126
void initialize() override
Fill in the options descriptions accordingly.
Definition: bset.cc:18
ProjectSettings & settings()
Definition: PrimClex.hh:116
PrimClex is the top-level data structure for a CASM project.
Definition: PrimClex.hh:52
void print_full_clust(std::ostream &out) const
std::string clexulator() const
const std::map< std::string, ClexDescription > & cluster_expansions() const
DirectoryStructure & dir
Definition: settings.cc:102
PrimClex & make_primclex_if_not(const CommandArgs &args, std::unique_ptr< PrimClex > &uniq_primclex)
If !_primclex, construct new PrimClex stored in uniq_primclex, then return reference to existing or c...
The PrimNeighborList gives the coordinates of UnitCell that are neighbors of the origin UnitCell...
Definition: NeighborList.hh:24
void write_basis(const SiteOrbitree &tree, const Structure &prim, jsonParser &json, double tol)
Write summary of basis functions.
Definition: AppIO.cc:474
fs::path clexulator_o(std::string project, std::string bset) const
Returns path to global clexulator o file.
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 error(const std::string &what)
Definition: Log.hh:86
#define ERR_EXISTING_FILE
pair_type bset
Definition: settings.cc:111
#define ERR_MISSING_INPUT_FILE
const ClexDescription & default_clex() const
SiteOrbitree make_orbitree(Structure &prim, const jsonParser &json, double _tol)
Make orbitree. For now specifically global.
Definition: PrimClex.cc:1097
const SiteOrbitree & orbitree(const ClexDescription &key) const
Definition: PrimClex.cc:996
const Structure & get_prim() const
const Access to primitive Structure
Definition: PrimClex.cc:260
#define ERR_MISSING_DEPENDS
#define ERR_NO_PROJ
#define ERR_INVALID_INPUT_FILE