CASM  1.1.0
A Clusters Approach to Statistical Mechanics
enum.cc
Go to the documentation of this file.
1 #include "casm/app/enum.hh"
2 
3 #include <cstring>
4 
12 #include "casm/casm_io/Log.hh"
14 #include "casm/clex/PrimClex.hh"
16 
17 namespace CASM {
18 namespace Completer {
19 
21 
23  bool required = false;
24 
25  // Standard options: --help, --desc, --settings, --input
26  m_desc.add_options()(
27  "help,h",
28  "Print help message including a list of all available methods.")(
29  "desc",
30  po::value<std::vector<std::string> >(&m_desc_vec)
31  ->multitoken()
32  ->zero_tokens()
33  ->value_name(ArgHandler::enummethod()),
34  "Print extended usage description. "
35  "Use '--desc [MethodName [MethodName2...]]' for detailed method "
36  "descriptions. "
37  "Partial matches of method names are acceptable.");
38  add_settings_suboption(required);
39  add_input_suboption(required);
40 
41  // `enum` method and method specific options:
42  // --method, --min, --max, --all, --scelnames, --confignames
43  //
44  // It is up to individual methods how to use these input, but prefer that CLI
45  // options take
46  // precendence in collisions with JSON input provided by --settings or
47  // --input
48  m_desc.add_options()(
49  "method,m",
50  po::value<std::string>(&m_method)->value_name(ArgHandler::enummethod()),
51  "Method to use: Can use method name (including partial matches) or "
52  "index.")(
53  "min", po::value<int>(&m_min_volume),
54  "Minimum volume supercell (integer, multiple of the prim volume)")(
55  "max", po::value<int>(&m_max_volume),
56  "Maximum volume supercell (integer, multiple of the prim volume)")(
57  "all,a", po::bool_switch(&m_all_existing)->default_value(false),
58  "Enumerate configurations for all existing supercells");
61 
62  // Options that control enumeration in a generic way: --filter, --verbosity,
63  // --dry-run
64  m_desc.add_options()(
65  "filter",
66  po::value<std::string>(&m_filter_str)->value_name(ArgHandler::query()),
67  "Filter configuration enumeration so that only configurations matching a "
68  "'casm query'-type expression are recorded");
71 
72  return;
73 }
74 } // namespace Completer
75 
76 const std::string EnumCommand::name = "enum";
77 
79  : APICommand<Completer::EnumOption>(_args, _opt),
80  m_enumerator_vector(nullptr) {}
81 
83  if (!in_project()) {
84  err_log().error("No casm project found");
85  err_log() << std::endl;
86  return ERR_NO_PROJ;
87  }
88 
89  if (vm().count("method") != 1) {
90  err_log() << "Error in 'casm enum'. The --method option is required."
91  << std::endl;
92  return ERR_INVALID_ARG;
93  }
94 
95  if (vm().count("settings") + vm().count("input") == 2) {
96  err_log() << "Error in 'casm enum'. The options --settings or --input may "
97  "not both be chosen."
98  << std::endl;
99  return ERR_INVALID_ARG;
100  }
101 
102  return 0;
103 }
104 
105 int EnumCommand::help() const {
106  log() << opt().desc() << std::endl;
108 
109  log() << "\nFor complete options description, use 'casm enum --desc "
110  "MethodName'.\n\n";
111 
112  return 0;
113 }
114 
115 int EnumCommand::desc() const {
116  if (opt().desc_vec().size()) {
117  log() << "\n";
118 
119  bool match = false;
120  for (const auto &in_name : opt().desc_vec()) {
121  for (const auto &interface_ptr : enumerators()) {
122  if (interface_ptr->name().substr(0, in_name.size()) == in_name) {
123  log() << interface_ptr->desc() << std::endl;
124  match = true;
125  break;
126  }
127  }
128  }
129 
130  if (!match) {
131  log() << "No match found. ";
133  }
134 
135  return 0;
136  } else {
137  log() << "\n";
138  log() << opt().desc() << std::endl;
139 
140  log() << "DESCRIPTION\n" << std::endl;
141 
142  log() << " casm enum --settings input.json "
143  " \n"
144  " casm enum --input '{...JSON...}' "
145  " \n"
146  " - Input settings in JSON format to run an enumeration. "
147  " \n\n";
148 
150 
151  log() << "\nFor complete options help for a particular method, \n"
152  "use 'casm enum --desc MethodName'.\n\n";
153 
154  log() << "Custom enumerator plugins can be added by placing source code \n"
155  "in the CASM project directory: \n"
156  " "
157  << primclex().dir().enumerator_plugins() << " \n\n";
158 
159  return 0;
160  }
161 }
162 
163 int EnumCommand::run() const {
164  // Select and execute an enumeration method from this->enumerators() based on
165  // --method value
166  // - accepts partial name matches if only one partial match
167  // - if no name match, attempt to interpret --method as index into
168  // this->enumerators()
169  // - otherwise provide a useful error message
170 
171  jsonParser json_options =
172  make_json_input(opt()); // JSON from --input string or --settings file
173  jsonParser cli_options_as_json{opt()}; // All CLI options as JSON object
174 
175  // find how many method names match the --method input value
176  auto enumeration_method_name_matches =
177  [&](notstd::cloneable_ptr<EnumInterfaceBase> const &interface_ptr) {
178  return interface_ptr->name().substr(0, opt().method().size()) ==
179  opt().method();
180  };
181  int count = std::count_if(enumerators().begin(), enumerators().end(),
182  enumeration_method_name_matches);
183 
184  if (count == 1) {
185  auto it = std::find_if(enumerators().begin(), enumerators().end(),
186  enumeration_method_name_matches);
187  (*it)->run(primclex(), json_options, cli_options_as_json);
188  return 0;
189  } else if (count < 1) {
190  // Attempt to understand --method input as index into method list
191  int method_index = -1;
192  try {
193  method_index = stoi(opt().method());
194  } catch (...) {
195  err_log() << "No match found for --method " << opt().method()
196  << std::endl;
198  return ERR_INVALID_ARG;
199  }
200 
201  if (method_index < 0 || method_index >= enumerators().size()) {
202  err_log() << "No match found for --method " << opt().method()
203  << std::endl;
205  return ERR_INVALID_ARG;
206  }
207 
208  auto it = enumerators().begin();
209  std::advance(it, method_index);
210  (*it)->run(primclex(), json_options, cli_options_as_json);
211  return 0;
212  } else if (count > 1) {
213  err_log() << "Multiple matches found for --method " << opt().method()
214  << std::endl;
216  return ERR_INVALID_ARG;
217  }
218  throw std::runtime_error("Unknown error in EnumCommand::run");
219 }
220 
222  if (m_enumerator_vector == nullptr) {
223  if (in_project()) {
224  // include plugins and standard enumerator methods
226  } else {
227  // only show standard enumerator methods (can't run if not in a project,
228  // but can see help messages)
231  }
232  }
233  return *m_enumerator_vector;
234 }
235 
236 void EnumCommand::print_names(std::ostream &sout,
237  EnumInterfaceVector const &enumerators) const {
238  sout << "The enumeration methods are:\n";
239  int counter = 0;
240  for (auto const &interface_ptr : enumerators) {
241  sout << " " << counter << ") " << interface_ptr->name() << std::endl;
242  ++counter;
243  }
244 }
245 
246 } // namespace CASM
#define ERR_NO_PROJ
Definition: errors.hh:13
#define ERR_INVALID_ARG
Definition: errors.hh:7
PrimClex & primclex() const
Definition: APICommand.cc:17
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
static std::string enummethod()
Get value_type string for enummethod mode completion.
Definition: Handlers.cc:72
static std::string query()
Get value_type string for query completion.
Definition: Handlers.cc:62
void initialize() override
Fill in the options descriptions accordingly.
Definition: enum.cc:22
std::string method() const
Definition: Handlers.hh:888
std::vector< std::string > m_desc_vec
Definition: Handlers.hh:895
void add_input_suboption(bool required=true)
Definition: Handlers.cc:610
void add_confignames_suboption()
Add a –confignames suboption.
Definition: Handlers.cc:691
const po::options_description & desc()
Get the program options, filled with the initialized values.
Definition: Handlers.cc:321
void add_settings_suboption(bool required=true)
Definition: Handlers.cc:588
po::options_description m_desc
Definition: Handlers.hh:260
void add_dry_run_suboption(std::string msg=default_dry_run_msg())
Definition: Handlers.cc:749
void add_scelnames_suboption()
Add a –scelnames suboption.
Definition: Handlers.cc:665
fs::path enumerator_plugins() const
Return enumerators plugin dir.
int run() const override
Definition: enum.cc:163
EnumInterfaceVector m_standard_enumerators
Definition: enum.hh:51
EnumInterfaceVector const & enumerators() const
Definition: enum.cc:221
EnumInterfaceVector const * m_enumerator_vector
Definition: enum.hh:52
int help() const override
Definition: enum.cc:105
EnumCommand(CommandArgs const &_args, Completer::EnumOption &_opt)
Definition: enum.cc:78
void print_names(std::ostream &sout, EnumInterfaceVector const &enumerators) const
Definition: enum.cc:236
int vm_count_check() const override
Definition: enum.cc:82
int desc() const override
Definition: enum.cc:115
static const std::string name
Definition: enum.hh:31
EnumInterfaceVector & get()
void error(const std::string &what)
Definition: Log.hh:129
EnumeratorHandler & enumerator_handler()
A 'cloneable_ptr' can be used in place of 'unique_ptr'.
ProjectSettings & settings()
Definition: PrimClex.cc:224
const DirectoryStructure & dir() const
Access DirectoryStructure object. Throw if not set.
Definition: PrimClex.cc:230
Main CASM namespace.
Definition: APICommand.hh:8
Log & log()
Definition: Log.hh:424
std::vector< notstd::cloneable_ptr< EnumInterfaceBase > > EnumInterfaceVector
jsonParser make_json_input(const OptionType &opt)
Definition: json_io_impl.hh:11
EnumInterfaceVector make_standard_enumerator_interfaces()
Log & err_log()
Definition: Log.hh:426
Data structure holding basic CASM command info.