CASM  1.1.0
A Clusters Approach to Statistical Mechanics
select.cc
Go to the documentation of this file.
1 #include "casm/app/select.hh"
2 
5 #include "casm/casm_io/Log.hh"
11 
12 namespace CASM {
13 
14 namespace Completer {
16 
17 const std::vector<std::string> &SelectOption::criteria_vec() const {
18  return m_criteria_vec;
19 }
20 
25  add_output_suboption("MASTER");
26 
27  m_desc.add_options()("json",
28  "Write JSON output (otherwise CSV, unless output "
29  "extension is '.json' or '.JSON')")(
30  "subset",
31  "Only write selected configurations to output. Can be used by itself or "
32  "in conjunction with other options")(
33  "xor", "Performs logical XOR on two configuration selections")(
34  "not", "Performs logical NOT on configuration selection")(
35  "or",
36  "Write configurations selected in any of the input lists. Equivalent to "
37  "logical OR")("and",
38  "Write configurations selected in all of the input lists. "
39  "Equivalent to logical AND")(
40  "set-on",
41  po::value<std::vector<std::string> >(&m_criteria_vec)
42  ->multitoken()
43  ->zero_tokens(),
44  "Add configurations to selection if they meet specified criteria. Call "
45  "using 'casm select --set-on [\"criteria\"]'")(
46  "set-off",
47  po::value<std::vector<std::string> >(&m_criteria_vec)
48  ->multitoken()
49  ->zero_tokens(),
50  "Remove configurations from selection if they meet specified criteria. "
51  "Call using 'casm select --set-off [\"criteria\"]'")(
52  "set",
53  po::value<std::vector<std::string> >(&m_criteria_vec)->multitoken(),
54  "Create a selection of Configurations that meet specified criteria. "
55  "Call using 'casm select --set [\"criteria\"]'")("force,f",
56  "Overwrite output file");
57 
58  return;
59 }
60 
61 } // namespace Completer
62 
63 // -- SelectCommandImplBase --------------------------------------------
64 
67  public:
69 
71 
72  virtual int help() const;
73 
74  virtual int desc() const;
75 
76  virtual int run() const;
77 
78  protected:
80 };
81 
83  : m_cmd(cmd) {}
84 
86  log() << std::endl << m_cmd.opt().desc() << std::endl;
87 
88  log()
89  << "Use query commands to specify objects that should be selected or "
90  "unselected.\n\n"
91 
92  "By default, the input and output selection is the MASTER selection, "
93  "but one \n"
94  "or more input selections may be specified via --selections (-c), and "
95  "the output \n"
96  "selection may be specified via --output (-o).\n\n"
97 
98  "For complete query options description, use '--help operators' or \n"
99  "'--help properties' along with '--type <typename>'.\n\n"
100 
101  "The type of objects acted on is specified via --type (-t).\n\n";
102 
103  m_cmd.print_names(log());
104  return 0;
105 }
106 
107 int SelectCommandImplBase::desc() const { return help(); }
108 
110  throw CASM::runtime_error("Unknown error in 'casm select'.", ERR_UNKNOWN);
111 }
112 
113 // -- SelectCommandImpl -----------------
114 
123 template <typename DataObject>
125  public:
126  SelectCommandImpl(const SelectCommand &cmd);
127 
128  int help() const override;
129 
130  int desc() const override;
131 
132  int run() const override;
133 
134  private:
135  int _count(std::string s) const { return m_cmd.vm().count(s); }
136 
137  const std::vector<fs::path> &_selection_paths() const {
138  return m_cmd.opt().selection_paths();
139  }
140 
141  fs::path _selection_paths(Index i) const { return _selection_paths()[i]; }
142 
143  const std::vector<std::string> &_criteria_vec() const {
144  return m_cmd.opt().criteria_vec();
145  }
146 
147  std::string _criteria() const;
148 
149  fs::path _output_path() const { return m_cmd.opt().output_path(); }
150 
151  void _set() const;
152 
153  void _set_on() const;
154 
155  void _set_off() const;
156 
157  void _and() const;
158 
159  void _or() const;
160 
161  void _xor() const;
162 
163  void _not() const;
164 
165  void _subset() const;
166 
167  void _write_input_stats() const;
168 
170  Log &log, bool only_selected) const;
171 
173  return m_data.dict();
174  }
175 
176  std::string _sel_str() const { return m_data.sel_str(); }
177 
178  double _sel_size() const { return m_data.sel_size(); }
179 
180  DB::Selection<DataObject> &_sel(Index i = 0) const { return m_data.sel(i); }
181 
182  private:
183  // access dictionary and selections
186 };
187 
188 template <typename DataObject>
190  : SelectCommandImplBase(cmd),
191  m_data(cmd),
192  m_Ntot(m_cmd.primclex().template generic_db<DataObject>().size()) {}
193 
194 template <typename DataObject>
196  if (!m_cmd.opt().help_opt_vec().size()) {
198  }
199 
200  for (const std::string &str : m_cmd.opt().help_opt_vec()) {
201  if (str.empty()) {
202  continue;
203  }
204 
205  if (str[0] == 'o') {
206  log() << "Available operators for use within selection criteria:"
207  << std::endl;
208  _dict().print_help(log(), DatumFormatterClass::Operator);
209  } else if (str[0] == 'p') {
210  log() << "Available property tags are currently:" << std::endl;
211  _dict().print_help(log(), DatumFormatterClass::Property);
212  }
213  log() << std::endl;
214  }
215  log() << std::endl;
216  return 0;
217 }
218 
219 template <typename DataObject>
221  return help();
222 }
223 
224 template <typename DataObject>
226  _write_input_stats();
227 
228  log().begin_lap();
229  if (_count("set")) {
230  _set();
231  } else if (_count("set-on")) {
232  _set_on();
233  } else if (_count("set-off")) {
234  _set_off();
235  } else if (_count("and")) {
236  _and();
237  } else if (_count("or")) {
238  _or();
239  } else if (_count("xor")) {
240  _xor();
241  } else if (_count("not")) {
242  _not();
243  } else {
244  err_log() << "ERROR: No valid command recognized." << std::endl;
245  help();
246  return ERR_INVALID_ARG;
247  }
248 
249  bool force_write = _count("force") || (_output_path().string() == "MASTER");
250  if (fs::exists(_output_path()) && !force_write) {
251  log() << "File " << _output_path()
252  << " already exists. Use --force to force overwrite." << std::endl;
253  return ERR_EXISTING_FILE;
254  }
255 
256  bool only_selected = false;
257  if (_count("subset")) {
258  _subset();
259  only_selected = true;
260  }
261 
262  log() << "selection time: " << log().lap_time() << " (s)\n" << std::endl;
263 
264  log().write("Selection");
265  _sel(0).write(_dict(), _output_path(), _count("json"), only_selected);
266 
267  log() << "write: " << _output_path() << "\n" << std::endl;
268 
269  log().custom("Output " + traits<DataObject>::short_name + " list",
270  _output_path().string());
271  _write_selection_stats(m_Ntot, _sel(0), log(), only_selected);
272 
273  log() << std::endl;
274 
275  return 0;
276 }
277 
278 template <typename DataObject>
280  if (_criteria_vec().size() == 0) {
281  return "";
282  } else if (_criteria_vec().size() == 1) {
283  return _criteria_vec()[0];
284  } else {
285  err_log()
286  << "ERROR: Selection criteria must be a single string. You provided "
287  << _criteria_vec().size() << " strings:\n";
288  for (const std::string &str : _criteria_vec())
289  err_log() << " - " << str << "\n";
290  throw runtime_error("Invalid selection criteria", ERR_INVALID_ARG);
291  }
292 }
293 
294 template <typename DataObject>
296  log().custom("set", _criteria());
297  _sel(0).set(_dict(), _criteria());
298 }
299 
300 template <typename DataObject>
302  log().custom("set-on", _criteria());
303  _sel(0).set(_dict(), _criteria(), true);
304 }
305 
306 template <typename DataObject>
308  log().custom("set-off", _criteria());
309  _sel(0).set(_dict(), _criteria(), false);
310 }
311 
312 template <typename DataObject>
314  log().custom(std::string("and(") + _sel_str() + ")");
315  for (int i = 1; i < _sel_size(); i++) {
316  for (const auto &val : _sel(i).data()) {
317  auto find_it = _sel(0).data().find(val.first);
318  if (find_it != _sel(0).data().end()) {
319  find_it->second = (find_it->second && val.second);
320  } else {
321  _sel(0).data()[val.first] = false;
322  }
323  }
324  }
325 }
326 
327 template <typename DataObject>
329  log().custom(std::string("or(") + _sel_str() + ")");
330  for (int i = 1; i < _sel_size(); i++) {
331  for (const auto &val : _sel(i).data()) {
332  if (val.second) {
333  _sel(0).data()[val.first] = true;
334  }
335  }
336  }
337 }
338 
339 template <typename DataObject>
341  log().custom(_selection_paths(0).string() + " xor " +
342  _selection_paths(1).string());
343  for (const auto &val : _sel(1).data()) {
344  // if not selected in second, use 'sel(0)' 'is_selected' value
345  if (!val.second) {
346  continue;
347  }
348  // else, if selected in second:
349 
350  // if not in 'sel(0)' insert selected
351  auto find_it = _sel(0).data().find(val.first);
352  if (find_it == _sel(0).data().end()) {
353  _sel(0).data().insert(val);
354  }
355  // else, use opposite of sel(0) 'is_selected' value
356  else {
357  find_it->second = !find_it->second;
358  }
359  }
360 }
361 
362 template <typename DataObject>
364  log().custom(std::string("not ") + _selection_paths(0).string());
365  for (auto &value : _sel(0).data()) {
366  value.second = !value.second;
367  }
368 }
369 
370 template <typename DataObject>
372  auto it = _sel(0).data().cbegin();
373  auto end = _sel(0).data().cend();
374  while (it != end) {
375  if (!it->second) {
376  it = _sel(0).data().erase(it);
377  } else {
378  ++it;
379  }
380  }
381 }
382 
383 template <typename DataObject>
385  // ---- write starting stats ----
386  log().custom("Input " + traits<DataObject>::short_name + " list",
387  _selection_paths(0).string());
388  _write_selection_stats(m_Ntot, _sel(0), log(), false);
389  log() << std::endl;
390 
391  for (int i = 1; i < _selection_paths().size(); ++i) {
392  log().custom("Input " + traits<DataObject>::short_name + " list",
393  _selection_paths(i).string());
394  _write_selection_stats(m_Ntot, _sel(i), log(), false);
395  log() << std::endl;
396  }
397 }
398 
399 template <typename DataObject>
401  Index Ntot, const DB::Selection<DataObject> &sel, Log &log,
402  bool only_selected) const {
403  auto Nselected = sel.selected_size();
404  auto Ninclude = only_selected ? Nselected : sel.size();
405 
406  log << "# " + traits<DataObject>::short_name + "s in this project: " << Ntot
407  << "\n";
408  log << "# " + traits<DataObject>::short_name + "s included in this list: "
409  << Ninclude << "\n";
410  log << "# " + traits<DataObject>::short_name + "s selected in this list: "
411  << Nselected << "\n";
412 }
413 
414 // -- class SelectCommand ----------------------------------------------------
415 
416 const std::string SelectCommand::name = "select";
417 
420  : APICommand<Completer::SelectOption>(_args, _opt) {}
421 
423 
425  if (!in_project()) {
426  err_log().error("No casm project found");
427  err_log() << std::endl;
428  return ERR_NO_PROJ;
429  }
430 
431  std::string cmd;
432  std::vector<std::string> allowed_cmd = {"and", "or", "xor", "not",
433  "set-on", "set-off", "set"};
434 
435  Index num_cmd(0);
436  for (const std::string &cmd_str : allowed_cmd) {
437  if (vm().count(cmd_str)) {
438  num_cmd++;
439  cmd = cmd_str;
440  }
441  }
442 
443  if (num_cmd > 1) {
444  err_log() << "Error in 'casm select'. No more than one of the following "
445  "may be used: "
446  << allowed_cmd << std::endl;
447  return ERR_INVALID_ARG;
448  } else if (vm().count("subset") && vm().count("selections") &&
449  opt().selection_paths().size() != 1) {
450  err_log()
451  << "ERROR: 'casm select --subset' expects zero or one list as argument."
452  << std::endl;
453  return ERR_INVALID_ARG;
454  }
455 
456  if (!vm().count("output") &&
457  (cmd == "or" || cmd == "and" || cmd == "xor" || cmd == "not")) {
458  err_log() << "ERROR: 'casm select --" << cmd
459  << "' expects an --output file." << std::endl;
460  return ERR_INVALID_ARG;
461  }
462 
463  if ((cmd == "set-on" || cmd == "set-off" || cmd == "set") &&
464  vm().count("selections") && opt().selection_paths().size() != 1) {
465  err_log() << "Error in 'casm select " << cmd << "'. "
466  << opt().selection_paths().size()
467  << " selections were specified, "
468  "but no more than one selection is allowed (MASTER list is "
469  "used if no "
470  "other is specified)."
471  << std::endl;
472  return ERR_INVALID_ARG;
473  }
474 
475  if (cmd == "xor" && opt().selection_paths().size() != 2) {
476  err_log()
477  << "ERROR: Option --xor requires exactly 2 selections as argument\n";
478  return ERR_INVALID_ARG;
479  }
480 
481  return 0;
482 }
483 
484 int SelectCommand::help() const { return impl().help(); }
485 
486 int SelectCommand::desc() const { return impl().desc(); }
487 
488 int SelectCommand::run() const { return impl().run(); }
489 
491  if (!m_impl) {
492  if (in_project()) {
493  if (!opt().db_type_opts().count(opt().db_type())) {
494  std::stringstream msg;
495  msg << "--type " << opt().db_type() << " is not allowed for 'casm "
496  << name << "'.";
497  print_names(err_log());
498  throw CASM::runtime_error(msg.str(), ERR_INVALID_ARG);
499  }
500 
501  DB::for_type_short(opt().db_type(),
503  } else {
504  m_impl = notstd::make_unique<SelectCommandImplBase>(*this);
505  }
506  }
507  return *m_impl;
508 }
509 
510 void SelectCommand::print_names(std::ostream &sout) const {
511  sout << "The allowed types are:\n";
512 
513  for (const auto &db_type : opt().db_type_opts()) {
514  sout << " " << db_type << std::endl;
515  }
516 }
517 
518 } // namespace CASM
std::set< std::string > & s
#define ERR_NO_PROJ
Definition: errors.hh:13
#define ERR_UNKNOWN
Definition: errors.hh:10
#define ERR_EXISTING_FILE
Definition: errors.hh:22
#define ERR_INVALID_ARG
Definition: errors.hh:7
bool in_project() const
Definition: APICommand.cc:15
const OptionType & opt() const
Definition: APICommand.hh:61
const po::variables_map & vm() const
Definition: APICommand.hh:59
void add_selections_suboption(const fs::path &_default="MASTER")
Add –selections suboption (defaults to MASTER)
Definition: Handlers.cc:443
const po::options_description & desc()
Get the program options, filled with the initialized values.
Definition: Handlers.cc:321
po::options_description m_desc
Definition: Handlers.hh:260
void add_db_type_suboption(std::string _default, std::set< std::string > _configtype_opts)
Definition: Handlers.cc:536
void add_general_help_suboption()
Add a smart –help suboption that takes "properties" or "operators".
Definition: Handlers.cc:567
void add_output_suboption()
Add a –output suboption. Expects to allow "STDOUT" to print to screen.
Definition: Handlers.cc:626
const std::vector< std::string > & criteria_vec() const
Definition: select.cc:17
void initialize() override
Fill in the options descriptions accordingly.
Definition: select.cc:21
std::string db_type() const
Definition: Handlers.cc:555
const std::vector< fs::path > & selection_paths() const
Returns the string corresponding to add_config_suboption()
Definition: Handlers.cc:342
const fs::path output_path() const
Returns the path corresponding to add_output_suboption()
Definition: Handlers.cc:370
std::vector< std::string > m_criteria_vec
Definition: Handlers.hh:1004
Index selected_size() const
Definition: Selection.cc:275
Index size() const
Definition: Selection.cc:260
Definition: Log.hh:48
void custom(const std::string &what)
Definition: Log.hh:139
void begin_lap()
Definition: Log.cc:47
void error(const std::string &what)
Definition: Log.hh:129
double lap_time() const
Definition: Log.cc:49
void write(const std::string &what)
Definition: Log.hh:109
SelectCommandImplBase & impl() const
Definition: select.cc:490
std::unique_ptr< SelectCommandImplBase > m_impl
Definition: select.hh:77
int help() const override
Definition: select.cc:484
void print_names(std::ostream &sout) const
Definition: select.cc:510
int desc() const override
Definition: select.cc:486
static const std::string name
Definition: select.hh:56
SelectCommand(const CommandArgs &_args, Completer::SelectOption &_opt)
Definition: select.cc:418
int vm_count_check() const override
Definition: select.cc:424
int run() const override
Definition: select.cc:488
Defaults used if DataObject type doesn't matter or not given.
Definition: select.cc:66
virtual int desc() const
Definition: select.cc:107
SelectCommandImplBase(const SelectCommand &cmd)
Definition: select.cc:82
const SelectCommand & m_cmd
Definition: select.cc:79
virtual int help() const
Definition: select.cc:85
virtual ~SelectCommandImplBase()
Definition: select.cc:70
virtual int run() const
Definition: select.cc:109
const std::vector< fs::path > & _selection_paths() const
Definition: select.cc:137
std::string _criteria() const
Definition: select.cc:279
const DataFormatterDictionary< DataObject > & _dict() const
Definition: select.cc:172
DB::InterfaceData< DataObject > m_data
Definition: select.cc:184
SelectCommandImpl(const SelectCommand &cmd)
Definition: select.cc:189
void _and() const
Definition: select.cc:313
void _write_selection_stats(Index Ntot, const DB::Selection< DataObject > &sel, Log &log, bool only_selected) const
Definition: select.cc:400
void _set_on() const
Definition: select.cc:301
int run() const override
Definition: select.cc:225
void _write_input_stats() const
Definition: select.cc:384
void _not() const
Definition: select.cc:363
double _sel_size() const
Definition: select.cc:178
void _set() const
Definition: select.cc:295
DB::Selection< DataObject > & _sel(Index i=0) const
Definition: select.cc:180
int help() const override
Definition: select.cc:195
int desc() const override
Definition: select.cc:220
void _or() const
Definition: select.cc:328
void _subset() const
Definition: select.cc:371
int _count(std::string s) const
Definition: select.cc:135
void _set_off() const
Definition: select.cc:307
fs::path _output_path() const
Definition: select.cc:149
void _xor() const
Definition: select.cc:340
fs::path _selection_paths(Index i) const
Definition: select.cc:141
std::string _sel_str() const
Definition: select.cc:176
const std::vector< std::string > & _criteria_vec() const
Definition: select.cc:143
void for_type_short(std::string short_name, F f)
const std::set< std::string > & types_short()
std::set of all QueryTraits<DataObject>::short_name
Main CASM namespace.
Definition: APICommand.hh:8
Log & log()
Definition: Log.hh:424
std::string help()
Uses 'multiline_help<T>()' by default.
Definition: Help.hh:22
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
Log & err_log()
Definition: Log.hh:426
PrimClex * primclex
Definition: settings.cc:135
Data structure holding basic CASM command info.