CASM  1.1.0
A Clusters Approach to Statistical Mechanics
Selection.cc
Go to the documentation of this file.
2 #include "casm/casm_io/Log.hh"
10 #include "casm/global/errors.hh"
11 
12 namespace CASM {
13 
14 const std::string traits<DB::SELECTION_TYPE>::name = "selection";
15 
16 const std::multimap<DB::SELECTION_TYPE, std::vector<std::string> >
17  traits<DB::SELECTION_TYPE>::strval = {
18  {DB::SELECTION_TYPE::MASTER, {"MASTER", "Master", "master"}},
19  {DB::SELECTION_TYPE::ALL, {"ALL", "All", "all"}},
20  {DB::SELECTION_TYPE::NONE, {"NONE", "None", "none"}},
21  {DB::SELECTION_TYPE::EMPTY, {"EMPTY", "Empty", "empty"}},
23  {"CALCULATED", "Calculated", "calculated"}}};
24 
25 namespace Monte {
28 } // namespace Monte
29 } // namespace CASM
30 
31 // explicit template instantiations
32 #define INST_Selection(r, data, type) \
33  template class SelectionIterator<type, Selection<type>::base_iterator>; \
34  template class SelectionIterator<type, \
35  Selection<type>::base_const_iterator>; \
36  template class Selection<type>;
37 
38 namespace CASM {
39 namespace DB {
40 
41 namespace {
42 
43 // Initialization for "CALCULATED" depends on type:
44 
48 template <typename ObjType, typename IfConfigType<ObjType>::type * = nullptr>
49 void init_calculated(typename Selection<ObjType>::map_type &m_data,
50  Database<ObjType> &db) {
51  for (const auto &obj : db) {
52  m_data.insert(std::make_pair(obj.name(), is_calculated(obj)));
53  }
54 }
55 
59 template <typename ObjType, typename IfNotConfigType<ObjType>::type * = nullptr>
60 void init_calculated(typename Selection<ObjType>::map_type &m_data,
61  Database<ObjType> &db) {
62  std::stringstream msg;
63  msg << "Selection 'CALCULATED' is not allowed for type: "
64  << traits<ObjType>::short_name;
65  throw std::runtime_error(msg.str());
66 }
67 } // namespace
68 
69 // --- template<typename ObjType, typename BaseIterator> class SelectionIterator
70 // ---
71 
73 template <typename ObjType, typename BaseIterator>
75  return m_it->first;
76 }
77 
79 template <typename ObjType, typename BaseIterator>
82  return m_it->second;
83 }
84 
86 template <typename ObjType, typename BaseIterator>
88  return m_it->second;
89 }
90 
92 template <typename ObjType, typename BaseIterator>
94  const Selection<ObjType> &_list, BaseIterator _it, bool _selected_only)
95  : m_list(&_list), m_it(_it), m_selected_only(_selected_only) {
96  if (m_selected_only && m_it != m_list->data().end() &&
97  m_it->second == false) {
98  increment();
99  }
100 }
101 
103 template <typename ObjType, typename BaseIterator>
105  ++m_it;
106  while (m_selected_only && m_it != m_list->data().end() &&
107  m_it->second == false) {
108  ++m_it;
109  }
110 }
111 
113 template <typename ObjType, typename BaseIterator>
115  --m_it;
116  while (m_selected_only && m_it != m_list->data().begin() &&
117  m_it->second == false) {
118  --m_it;
119  }
120 }
121 
123 template <typename ObjType, typename BaseIterator>
125  return *(m_list->db().find(m_it->first));
126 }
127 
129 template <typename ObjType, typename BaseIterator>
131  const SelectionIterator &B) const {
132  return m_it == B.m_it;
133 }
134 
135 // --- template<typename ObjType> class Selection ---
136 
138 template <typename ObjType>
139 Selection<ObjType>::Selection() : m_db(nullptr), m_primclex(nullptr){};
140 
142 template <typename ObjType>
144  fs::path selection_path)
145  : Selection(_primclex.db<ObjType>(), selection_path) {}
146 
147 template <typename ObjType>
148 Selection<ObjType>::Selection(Database<ObjType> &_db, fs::path selection_path)
149  : m_db(&_db),
150  m_primclex(&m_db->primclex()),
151  m_name(selection_path.string()) {
152  auto _match = matches<DB::SELECTION_TYPE>(selection_path.string());
153 
154  if (_match.size() == 1 || selection_path.empty()) {
156  selection_path.empty() ? DB::SELECTION_TYPE::MASTER : *_match.begin();
157 
158  if (sel == DB::SELECTION_TYPE::MASTER) {
159  fs::path master_selection_path;
160  if (primclex().has_dir()) {
161  master_selection_path =
162  primclex().dir().template master_selection<ObjType>();
163  }
164  if (!master_selection_path.empty() && fs::exists(master_selection_path)) {
165  fs::ifstream select_file(master_selection_path);
166  read(select_file);
167  select_file.close();
168  } else {
169  for (const auto &obj : db()) {
170  m_data.insert(std::make_pair(obj.name(), false));
171  }
172  }
173  } else if (sel == DB::SELECTION_TYPE::NONE) {
174  for (const auto &obj : db()) {
175  m_data.insert(std::make_pair(obj.name(), false));
176  }
177  } else if (sel == DB::SELECTION_TYPE::EMPTY) {
178  } else if (sel == DB::SELECTION_TYPE::ALL) {
179  for (const auto &obj : db()) {
180  m_data.insert(std::make_pair(obj.name(), true));
181  }
182  } else if (sel == DB::SELECTION_TYPE::CALCULATED) {
183  init_calculated(m_data, db());
184  }
185  } else {
186  if (!fs::exists(selection_path)) {
187  std::stringstream ss;
188  ss << "ERROR in parsing configuration selection name. \n"
189  << " " << singleline_help<DB::SELECTION_TYPE>() << "\n"
190  << " Received: '" << selection_path << "'\n"
191  << " No file named '" << selection_path << "'.";
192  throw std::runtime_error(ss.str());
193  }
194  m_name = fs::absolute(selection_path).string();
195  if (selection_path.extension() == ".json" ||
196  selection_path.extension() == ".JSON") {
197  from_json(jsonParser(selection_path));
198  } else {
199  fs::ifstream select_file(selection_path);
200  read(select_file);
201  select_file.close();
202  }
203  }
204 }
205 
206 template <typename ObjType>
208  return *m_primclex;
209 }
210 
211 template <typename ObjType>
213  if (!m_db) {
214  throw std::runtime_error(
215  "Error in Selection<ObjType>::db(): Database pointer invalid");
216  }
217  return *m_db;
218 }
219 
220 template <typename ObjType>
223  return boost::make_iterator_range(iterator(*this, m_data.begin(), false),
224  iterator(*this, m_data.end(), false));
225 }
226 
227 template <typename ObjType>
230  return boost::make_iterator_range(
231  const_iterator(*this, m_data.begin(), false),
232  const_iterator(*this, m_data.end(), false));
233 }
234 
235 template <typename ObjType>
238  return boost::make_iterator_range(iterator(*this, m_data.begin(), true),
239  iterator(*this, m_data.end(), true));
240 }
241 
242 template <typename ObjType>
245  return boost::make_iterator_range(const_iterator(*this, m_data.begin(), true),
246  const_iterator(*this, m_data.end(), true));
247 }
248 
249 template <typename ObjType>
251  return m_data;
252 }
253 
254 template <typename ObjType>
256  return m_data;
257 }
258 
259 template <typename ObjType>
261  return m_data.size();
262 }
263 
264 template <typename ObjType>
265 const std::vector<std::string> &Selection<ObjType>::col_headers() const {
266  return m_col_headers;
267 }
268 
269 template <typename ObjType>
270 const std::string &Selection<ObjType>::name() const {
271  return m_name;
272 }
273 
274 template <typename ObjType>
276  return boost::distance(selected());
277 }
278 
280 template <typename ObjType>
281 bool Selection<ObjType>::is_selected(const std::string &name_or_alias) const {
282  auto it = m_data.find(db().name(name_or_alias));
283  if (it == m_data.end()) {
284  return false;
285  }
286  return it->second;
287 }
288 
290 template <typename ObjType>
292  const std::string &criteria) {
293  try {
294  if (criteria.size()) {
295  DataFormatter<ObjType> tformat(dict.parse(criteria));
296  auto it = all().begin();
297  auto end = all().end();
298  for (; it != end; ++it) {
299  ValueDataStream<bool> select_stream;
300  select_stream << tformat(*it);
301  if (select_stream.fail()) {
302  err_log() << "Warning: Unable to apply criteria \"" << criteria
303  << "\" to " << traits<ObjType>::name << " " << it.name()
304  << "\n";
305  continue;
306  }
307  it.is_selected() = select_stream.value();
308  }
309  }
310  } catch (std::exception &e) {
311  throw std::runtime_error(
312  std::string("Failure to select using criteria \"") + criteria +
313  "\" for " + traits<ObjType>::name +
314  "\n"
315  " Reason: " +
316  e.what());
317  }
318 }
319 
321 template <typename ObjType>
323  const std::string &criteria, bool value) {
324  try {
325  if (criteria.size()) {
326  DataFormatter<ObjType> tformat(dict.parse(criteria));
327  auto it = all().begin();
328  auto end = all().end();
329  for (; it != end; ++it) {
330  if (it.is_selected() == value) {
331  continue;
332  }
333  ValueDataStream<bool> select_stream;
334  if (select_stream.fail()) {
335  err_log() << "Warning: Unable to apply criteria \"" << criteria
336  << "\" to " << traits<ObjType>::name << " " << it.name()
337  << "\n";
338  continue;
339  }
340 
341  select_stream << tformat(*it);
342  if (select_stream.value()) {
343  it.is_selected() = value;
344  }
345  }
346  } else {
347  auto it = all().begin();
348  auto end = all().end();
349  for (; it != end; ++it) {
350  it.is_selected() = value;
351  }
352  }
353  } catch (std::exception &e) {
354  throw std::runtime_error(
355  std::string("Failure to select using criteria \"") + criteria +
356  "\" for " + traits<ObjType>::name +
357  "\n"
358  " Reason: " +
359  e.what());
360  }
361 }
362 
364 template <typename ObjType>
365 void Selection<ObjType>::read(std::istream &_input) {
366  std::string tname_or_alias;
367  bool tselect;
368  _input >> std::ws;
369  if (_input.peek() == '#') {
370  _input.get();
371  // discard first two columns (name_or_alias, selected)
372  _input >> tname_or_alias;
373  _input >> tname_or_alias;
374  std::getline(_input, tname_or_alias, '\n');
375  m_col_headers.clear();
376  boost::split(m_col_headers, tname_or_alias, boost::is_any_of(" \t"),
377  boost::token_compress_on);
378  //_input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
379  }
380  while (_input >> tname_or_alias >> tselect) {
381  // skip unknown quietly (not sure what is best)
382  // this typically arises in cases an object was deleted
383  if (db().find(db().name(tname_or_alias)) == db().end()) {
384  continue;
385  }
386  m_data[db().name(tname_or_alias)] = tselect;
387  _input.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
388  }
389 }
390 
392 template <typename ObjType>
394  if (!_json.is_array()) {
395  std::cerr << "CRITICAL ERROR: Unable to initialize a Selection from passed "
396  "JSON input."
397  << std::endl
398  << " JSON input must be an array of records."
399  << std::endl
400  << " Exiting..." << std::endl;
401  exit(1);
402  }
403 
404  std::string tname;
405  bool tselected;
406  bool contains_name;
407 
408  std::set<std::string> prop_set;
409  m_data.clear();
410 
411  for (Index i = 0; i < _json.size(); i++) {
412  auto it(_json[i].cbegin()), it_end(_json[i].cend());
413 
414  contains_name = false;
415  tselected = true; // default to selected
416 
417  for (; it != it_end; ++it) {
418  // for compatibility, include "configname" also
419  if (it.name() == "name" || it.name() == "alias" ||
420  it.name() == "alias_or_name" || it.name() == "configname") {
421  tname = db().name(it->get<std::string>());
422  contains_name = true;
423  } else if (it.name() == "selected") {
424  tselected = it->get<bool>();
425  } else {
426  prop_set.insert(it.name());
427  }
428  }
429 
430  if (!contains_name) {
431  throw std::runtime_error(
432  std::string("CRITICAL ERROR: Field 'name' is missing from ") +
433  std::to_string(i) +
434  " of json Array passed to Selection::from_json()." +
435  " This field is required.");
436  }
437 
438  m_data[tname] = tselected;
439  }
440 
441  m_col_headers = std::vector<std::string>(prop_set.begin(), prop_set.end());
442 
443  return _json;
444 }
445 
447 template <typename ObjType>
449  const DataFormatterDictionary<ObjType> &_dict, jsonParser &_json,
450  bool only_selected) const {
451  _json.put_array();
452 
453  DataFormatter<ObjType> tformat(
454  alias_or_name<ObjType>(),
455  datum_formatter_alias("selected", Selected<ObjType>(*this)));
456 
457  tformat.append(_dict.parse(m_col_headers));
458 
459  if (only_selected) {
460  _json = tformat(selected().begin(), selected().end());
461  } else {
462  _json = tformat(all().begin(), all().end());
463  }
464 
465  return _json;
466 }
467 
469 template <typename ObjType>
471  std::ostream &_out, bool only_selected) const {
472  DataFormatter<ObjType> tformat(
473  alias_or_name<ObjType>(),
474  datum_formatter_alias("selected", Selected<ObjType>(*this)));
475 
476  tformat.append(_dict.parse(m_col_headers));
477 
478  if (only_selected) {
479  _out << tformat(selected().begin(), selected().end());
480  } else {
481  _out << tformat(all().begin(), all().end());
482  }
483 }
484 
486 template <typename ObjType>
488  const fs::path &_out_path, bool write_json,
489  bool only_selected) const {
490  fs::path out_path(_out_path);
491  auto _matches = matches<DB::SELECTION_TYPE>(out_path.string());
492  if (_matches.size() == 1 && *_matches.begin() == DB::SELECTION_TYPE::MASTER) {
493  out_path = primclex().dir().template master_selection<ObjType>();
494  }
495 
496  if (write_json || out_path.extension() == ".json" ||
497  out_path.extension() == ".JSON") {
498  jsonParser json;
499  this->to_json(dict, json, only_selected);
500  SafeOfstream sout;
501  sout.open(out_path);
502  json.print(sout.ofstream());
503  sout.close();
504  } else {
505  SafeOfstream sout;
506  sout.open(out_path);
507  this->print(dict, sout.ofstream(), only_selected);
508  sout.close();
509  }
510 }
511 
512 BOOST_PP_SEQ_FOR_EACH(INST_Selection, _, CASM_DB_TYPES)
513 } // namespace DB
514 } // namespace CASM
#define CASM_DB_TYPES
#define INST_Selection(r, data, type)
Definition: Selection.cc:32
#define ENUM_JSON_IO_DEF(ENUM)
Definition: json_io.hh:15
#define ENUM_IO_DEF(ENUM)
Definition: stream_io.hh:13
Returns true if configuration is specified in given selection (default: MASTER)
Definition: Selected.hh:20
std::map< std::string, bool, Compare > map_type
Definition: Selection.hh:121
Selection()
Default construct into invalid state.
Definition: Selection.cc:139
Index size() const
Definition: Selection.cc:260
void decrement()
boost::iterator_facade implementation
Definition: Selection.cc:114
std::string name() const
Name of object the iterator points at.
Definition: Selection.cc:74
bool equal(const SelectionIterator &B) const
boost::iterator_facade implementation
Definition: Selection.cc:130
bool_type & is_selected()
Reference to value 'is_selected'.
Definition: Selection.cc:81
void increment()
boost::iterator_facade implementation
Definition: Selection.cc:104
CASM_TMP::ConstSwitch< std::is_same< BaseIterator, std::map< std::string, bool >::const_iterator >::value, bool > bool_type
Definition: Selection.hh:53
const ObjType & dereference() const
boost::iterator_facade implementation
Definition: Selection.cc:124
SelectionIterator()
Default constructor (equals end)
Definition: Selection.hh:56
const Selection< ObjType > * m_list
Definition: Selection.hh:95
Parsing dictionary for constructing a DataFormatter<DataObject> object.
DataFormatter< DataObject > parse(const std::string &input) const
Use the vector of strings to build a DataFormatter<DataObject>
Extract data from objects of 'DataObject' class.
void append(const DataFormatter< DataObject > &_tail)
bool fail() const
Definition: DataStream.hh:60
PrimClex is the top-level data structure for a CASM project.
Definition: PrimClex.hh:55
Write to a temporary file to ensure a good write, then rename.
Definition: SafeOfstream.hh:31
void close()
Closes stream, and if not a failed write, removes "file" and renames "file.tmp" to "file".
Definition: SafeOfstream.hh:84
void open(fs::path name, std::string tmp_ext="tmp")
Opens "file.tmp" for writing, with intended final target "file".
Definition: SafeOfstream.hh:65
fs::ofstream & ofstream()
Access underlying stream.
Definition: SafeOfstream.hh:80
const T & value() const
Definition: DataStream.hh:256
size_type size() const
Definition: jsonParser.cc:487
bool is_array() const
Check if array type.
Definition: jsonParser.cc:275
jsonParser & put_array()
Puts new empty JSON array.
Definition: jsonParser.hh:362
void print(std::ostream &stream, unsigned int indent=2, unsigned int prec=12) const
Print json to stream.
Definition: jsonParser.cc:188
DatumFormatterAlias< DataObject > datum_formatter_alias(const std::string &_name, const std::string &_command, const DataFormatterDictionary< DataObject > &_dict, const std::string &_help="")
Make a DatumFormatterAlias.
std::string to_string(ENUM val)
Return string representation of enum class.
Definition: io_traits.hh:172
GenericDatumFormatter< std::string, ConfigEnumDataType > name()
GenericDatumFormatter< bool, ConfigEnumDataType > selected()
SELECTION_TYPE
Definition: Selection.hh:16
Main CASM namespace.
Definition: APICommand.hh:8
jsonParser & to_json(const ClexDescription &desc, jsonParser &json)
bool is_calculated(const ConfigType &config, std::string calctype="")
Return true if all required properties have been been calculated for the configuration.
Definition: Calculable.cc:137
void from_json(ClexDescription &desc, const jsonParser &json)
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:16
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
T max(const T &A, const T &B)
Definition: CASM_math.hh:95
PrimClex * primclex
Definition: settings.cc:135
ProjectSettings & set
Definition: settings.cc:137
Log & err_log
Definition: settings.cc:140