CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
query.cc
Go to the documentation of this file.
1 #include <string>
2 #include <boost/algorithm/string.hpp>
4 #include "casm/clex/ConfigIO.hh"
7 
8 namespace CASM {
9 
10  void query_help(const DataFormatterDictionary<Configuration> &_dict, std::ostream &_stream, std::vector<std::string > help_opt_vec) {
11  _stream << "Prints the properties for a set of configurations for the set of currently selected" << std::endl
12  << "configurations or for a set of configurations specifed by a selection file." << std::endl
13  << std::endl
14  << "Property values are output in column-separated (default) or JSON format. By default, " << std::endl
15  << "entries for 'name' and 'selected' values are included in the output. " << std::endl
16  << std::endl;
17 
18  for(const std::string &help_opt : help_opt_vec) {
19  if(help_opt.empty())
20  continue;
21 
22  if(help_opt[0] == 'o') {
23  _stream << "Available operators for use within queries:" << std::endl;
25  }
26  else if(help_opt[0] == 'p') {
27  _stream << "Available property tags are currently:" << std::endl;
29  }
30  _stream << std::endl;
31  }
32  _stream << std::endl;
33  }
34 
35  namespace Completer {
36 
38 
44 
45  m_desc.add_options()
46  ("columns,k", po::value<std::vector<std::string> >(&m_columns_vec)->multitoken()->zero_tokens()->value_name(ArgHandler::query()), "List of values you want printed as columns")
47  ("json,j", po::value(&m_json_flag)->default_value(false)->zero_tokens(), "Print in JSON format (CSV otherwise, unless output extension is .json/.JSON)")
48  ("verbatim,v", po::value(&m_verbatim_flag)->default_value(false)->zero_tokens(), "Print exact properties specified, without prepending 'name' and 'selected' entries")
49  ("all,a", "Print results all configurations in input selection, whether or not they are selected.")
50  ("no-header,n", po::value(&m_no_header_flag)->default_value(false)->zero_tokens(), "Print without header (CSV only)")
51  ("alias", po::value<std::vector<std::string> >(&m_new_alias_vec)->multitoken(),
52  "Create an alias for a query that will persist within this project. "
53  "Ex: 'casm query --alias is_Ni_dilute = lt(atom_frac(Ni),0.10001)'")
54  ("write-pos", "Write POS file for each configuration");
55 
56  return;
57  }
58 
59  const std::vector<std::string> &QueryOption::columns_vec() const {
60  return m_columns_vec;
61  }
62 
63  const std::vector<std::string> &QueryOption::new_alias_vec() const {
64  return m_new_alias_vec;
65  }
66 
67  bool QueryOption::json_flag() const {
68  return m_json_flag;
69  }
70 
72  return m_verbatim_flag;
73  }
74 
76  return m_no_header_flag;
77  }
78 
79  }
80 
81  int query_command(const CommandArgs &args) {
82 
83  std::string selection_str;
84  fs::path config_path, out_path;
85  std::vector<std::string> columns, help_opt_vec, new_alias;
86  po::variables_map vm;
87  bool json_flag(false), no_header(false), verbatim_flag(false), gz_flag(false);
88 
89  //po::options_description desc("'casm query' usage");
90  // Set command line options using boost program_options
91  Completer::QueryOption query_opt;
92 
93  try {
94  po::store(po::parse_command_line(args.argc, args.argv, query_opt.desc()), vm); // can throw
95 
98  if(vm.count("help")) {
99  args.log << std::endl << query_opt.desc() << std::endl;
100  }
101 
102  po::notify(vm); // throws on error, so do after help in case of problems
103 
104  selection_str = query_opt.selection_path().string();
105  out_path = query_opt.output_path();
106  columns = query_opt.columns_vec();
107  help_opt_vec = query_opt.help_opt_vec();
108  new_alias = query_opt.new_alias_vec();
109  json_flag = query_opt.json_flag();
110  no_header = query_opt.no_header_flag();
111  verbatim_flag = query_opt.verbatim_flag();
112  gz_flag = query_opt.gzip_flag();
113 
116  if(vm.count("help")) {
117  if(args.root.empty()) {
118  auto dict = make_dictionary<Configuration>();
119  query_help(dict, args.log, help_opt_vec);
120  }
121  else {
122  // set status_stream: where query settings and PrimClex initialization messages are sent
123  Log &status_log = (out_path.string() == "STDOUT") ? args.err_log : args.log;
124 
125  // If '_primclex', use that, else construct PrimClex in 'uniq_primclex'
126  // Then whichever exists, store reference in 'primclex'
127  std::unique_ptr<PrimClex> uniq_primclex;
128  if(out_path.string() == "STDOUT") {
129  args.log.set_verbosity(0);
130  }
131  PrimClex &primclex = make_primclex_if_not(args, uniq_primclex, status_log);
132  query_help(
133  primclex.settings().query_handler<Configuration>().dict(),
134  args.log,
135  help_opt_vec);
136  }
137  return 0;
138  }
139 
140 
141  }
142  catch(po::error &e) {
143  args.err_log << "ERROR: " << e.what() << std::endl << std::endl;
144  args.err_log << query_opt.desc() << std::endl;
145  return ERR_INVALID_ARG;
146  }
147  catch(std::exception &e) {
148  args.err_log << "Unhandled Exception reached the top of main: "
149  << e.what() << ", application will now exit" << std::endl;
150  return ERR_UNKNOWN;
151  }
152 
153  if(!vm.count("alias") && !vm.count("columns")) {
154  args.log << std::endl << query_opt.desc() << std::endl;
155  }
156 
157  // set current path to project root
158  const fs::path &root = args.root;
159  if(root.empty()) {
160  args.err_log.error("No casm project found");
161  args.err_log << std::endl;
162  return ERR_NO_PROJ;
163  }
164 
165  if(vm.count("alias")) {
166 
167  ProjectSettings set(root);
168 
169  // get user input
170  std::string new_alias_str;
171  for(auto const &substr : new_alias) {
172  new_alias_str += substr;
173  }
174 
175  // parse new_alias_str to create formatter
176  auto it = std::find(new_alias_str.cbegin(), new_alias_str.cend(), '=');
177  std::string alias_name = boost::trim_copy(std::string(new_alias_str.cbegin(), it));
178  std::string alias_command = boost::trim_copy(std::string(++it, new_alias_str.cend()));
179 
180  try {
181  set.query_handler<Configuration>().add_alias(alias_name, alias_command);
182  set.commit();
183  return 0;
184  }
185  catch(std::runtime_error &e) {
186  args.err_log << "Unable to learn alias\n"
187  << " \"" << alias_name << " = " << alias_command << "\"\n"
188  << e.what() << std::endl;
189  return ERR_UNKNOWN;
190  }
191 
192  }
193  if(!vm.count("columns") && !vm.count("write-pos")) {
194  args.err_log << "ERROR: the option '--columns' or '--write-pos' is required but missing" << std::endl;
195  return ERR_INVALID_ARG;
196  }
197 
198 
199  // -------------------------------------------------------------------------
200  // perform query operation
201 
202  auto check_gz = [ = ](fs::path p) {
203  if(p.extension() == ".gz" || p.extension() == ".GZ") {
204  return true;
205  }
206  return false;
207  };
208 
209  auto check_json = [ = ](fs::path p) {
210  if(p.extension() == ".json" || p.extension() == ".JSON") {
211  return true;
212  }
213  return false;
214  };
215 
216 
217  // Checks for: X.json.gz / X.json / X.gz (also accepts .JSON or .GZ)
218  if(check_gz(out_path)) {
219  gz_flag = true;
220  json_flag = check_json(out_path.stem()) || json_flag;
221  }
222  else {
223  json_flag = check_json(out_path) || json_flag;
224  }
225 
226  // set output_stream: where the query results are written
227  std::unique_ptr<std::ostream> uniq_fout;
228  std::ostream &output_stream = make_ostream_if(vm.count("output"), args.log, uniq_fout, out_path, gz_flag);
229  output_stream << FormatFlag(output_stream).print_header(!no_header);
230 
231  // set status_stream: where query settings and PrimClex initialization messages are sent
232  Log &status_log = (out_path.string() == "STDOUT") ? args.err_log : args.log;
233 
234  // If '_primclex', use that, else construct PrimClex in 'uniq_primclex'
235  // Then whichever exists, store reference in 'primclex'
236  std::unique_ptr<PrimClex> uniq_primclex;
237  if(out_path.string() == "STDOUT") {
238  args.log.set_verbosity(0);
239  }
240  PrimClex &primclex = make_primclex_if_not(args, uniq_primclex, status_log);
241 
242  // Get configuration selection
243  ConstConfigSelection selection(primclex, selection_str);
244 
245  // Print info
246  status_log << "Print:" << std::endl;
247  for(int p = 0; p < columns.size(); p++) {
248  status_log << " - " << columns[p] << std::endl;
249  }
250  if(vm.count("output")) {
251  if(out_path.string() == "STDOUT") {
252  status_log << "to " << out_path << std::endl;
253  }
254  else {
255  status_log << "to " << fs::absolute(out_path) << std::endl;
256  }
257  }
258  status_log << std::endl;
259 
260  // Construct DataFormatter
261  primclex.settings().query_handler<Configuration>().set_selected(selection);
263 
264  try {
265 
266  std::vector<std::string> all_columns;
267  if(!verbatim_flag) {
268  all_columns.push_back("configname");
269  all_columns.push_back("selected");
270  }
271  all_columns.insert(all_columns.end(), columns.cbegin(), columns.cend());
272 
273  formatter.append(primclex.settings().query_handler<Configuration>().dict().parse(all_columns));
274 
275  }
276  catch(std::exception &e) {
277  args.err_log << "Parsing error: " << e.what() << "\n\n";
278  return ERR_INVALID_ARG;
279  }
280 
281  try {
282 
283  auto begin = vm.count("all") ? selection.config_begin() : selection.selected_config_begin();
284  auto end = vm.count("all") ? selection.config_end() : selection.selected_config_end();
285 
286  if(vm.count("write-pos")) {
287  for(auto it = begin; it != end; ++it) {
288  it->write_pos();
289  }
290  }
291 
292  // JSON output block
293  if(json_flag) {
294  jsonParser json;
295 
296  //sout << "Read in config selection... it is:\n" << selection;
297  json = formatter(begin, end);
298 
299  output_stream << json;
300  }
301  // CSV output block
302  else {
303  //sout << "Read in config selection... it is:\n" << selection;
304  output_stream << formatter(begin, end);
305  }
306 
307  }
308  catch(std::exception &e) {
309  args.err_log << "Initialization error: " << e.what() << "\n\n";
310  return ERR_UNKNOWN;
311  }
312 
313  if(!uniq_fout) {
314  status_log << "\n -Output printed to terminal, since no output file specified-\n";
315  }
316 
317  status_log << " DONE." << std::endl << std::endl;
318 
319  return 0;
320  };
321 }
322 
323 
void query_help(const DataFormatterDictionary< Configuration > &_dict, std::ostream &_stream, std::vector< std::string > help_opt_vec)
Definition: query.cc:10
Data structure holding basic CASM command info.
std::vector< std::string > m_columns_vec
Definition: Handlers.hh:377
std::vector< std::string > m_new_alias_vec
Definition: Handlers.hh:379
void add_output_suboption()
Add a –output suboption. Expects to allow "STDOUT" to print to screen.
Definition: Handlers.cc:326
void commit() const
Save settings to project settings file.
#define ERR_UNKNOWN
bool json_flag() const
Definition: query.cc:67
bool print_header() const
Definition: FormatFlag.hh:33
#define ERR_INVALID_ARG
PrimClex * primclex
Definition: settings.cc:101
iterator selected_config_begin()
void add_general_help_suboption()
Add a smart –help suboption that takes "properties" or "operators".
Definition: Handlers.cc:283
void add_configlist_suboption(const fs::path &_default="MASTER")
Add –config suboption (defaults to MASTER)
Definition: Handlers.cc:238
Main CASM namespace.
Definition: complete.cpp:8
const fs::path & selection_path() const
Returns the string corresponding to add_config_suboption()
Definition: Handlers.cc:168
ProjectSettings & set
Definition: settings.cc:103
int query_command(const CommandArgs &args)
Definition: query.cc:81
void print_help(std::ostream &_stream, typename BaseDatumFormatter< DataObject >::FormatterType ftype, int width=60, int separation=8) const
Generates formatted help using the 'name' and 'description' of all contained BaseDatumFormatter.
void push_back(const BaseDatumFormatter< DataObject > &new_formatter, const std::string &args)
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.
const std::vector< std::string > & help_opt_vec() const
Returns the list of strings corresponding to add_general_help_suboption()
Definition: Handlers.cc:196
static std::string query()
Get value_type string for query completion.
Definition: Handlers.cc:51
QueryHandler< DataObject > & query_handler()
po::options_description m_desc
Boost program options. All the derived classes have them, but will fill them up themselves.
Definition: Handlers.hh:126
ProjectSettings & settings()
Definition: PrimClex.hh:116
bool gzip_flag() const
Returns the value assigned for add_gzip_suboption()
Definition: Handlers.cc:192
Iterator find(Iterator begin, Iterator end, const T &value, BinaryCompare q)
Equivalent to std::find(begin, end, value), but with custom comparison.
Definition: algorithm.hh:10
PrimClex is the top-level data structure for a CASM project.
Definition: PrimClex.hh:52
void add_gzip_suboption()
Add a –gzip suboption. The value will default to false unless overridden by the derived class...
Definition: Handlers.cc:332
std::ostream & make_ostream_if(bool output, std::ostream &sout, std::unique_ptr< std::ostream > &fout, fs::path out_path, bool gzip)
Return a reference to proper std::ostream.
const std::vector< std::string > & columns_vec() const
Definition: query.cc:59
Abstract base class from which all other DatumFormatter classes inherit.
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...
Extract data from objects of 'DataObject' class.
bool no_header_flag() const
Definition: query.cc:75
void set_verbosity(int _verbosity)
Definition: Log.cc:42
void append(const DataFormatter< DataObject > &_tail)
void error(const std::string &what)
Definition: Log.hh:86
const fs::path output_path() const
Returns the path corresponding to add_output_suboption()
Definition: Handlers.cc:188
const std::vector< std::string > & new_alias_vec() const
Definition: query.cc:63
Definition: Log.hh:9
void initialize() override
Fill in the options descriptions accordingly.
Definition: query.cc:39
Parsing dictionary for constructing a DataFormatter object.
A Configuration represents the values of all degrees of freedom in a Supercell.
#define ERR_NO_PROJ
bool verbatim_flag() const
Definition: query.cc:71