CASM  1.1.0
A Clusters Approach to Statistical Mechanics
jsonDatabase.cc
Go to the documentation of this file.
2 
3 #include <boost/filesystem.hpp>
4 #include <boost/range/iterator_range.hpp>
5 
16 
17 // for testing:
19 
20 namespace CASM {
21 
22 const std::string traits<DB::jsonDB>::name = "jsonDB";
23 
24 const std::string traits<DB::jsonDB>::version = "1.0";
25 
26 namespace DB {
27 
28 namespace {
29 struct InsertImpl {
30  InsertImpl(DatabaseHandler &_db_handler) : db_handler(_db_handler) {}
31  DatabaseHandler &db_handler;
32 
33  template <typename T>
34  void eval() {
35  db_handler.insert<T>(
37  notstd::make_unique<jsonDatabase<T> >(db_handler.primclex()));
38  }
39 };
40 } // namespace
41 
42 namespace {
43 
44 struct InsertPropsImpl {
45  InsertPropsImpl(DatabaseHandler &_db_handler)
46  : db_handler(_db_handler),
47  primclex(_db_handler.primclex()),
48  dir(primclex.dir()),
49  json_dir(dir.root_dir()) {}
50 
51  DatabaseHandler &db_handler;
52  const PrimClex &primclex;
53  const DirectoryStructure &dir;
54  jsonDB::DirectoryStructure json_dir;
55 
56  template <typename T>
57  void eval() {
58  for (auto calc_type : dir.all_calctype()) {
59  fs::path location = json_dir.props_list<T>(calc_type);
60  db_handler.insert_props<T>(traits<jsonDB>::name, calc_type,
61  notstd::make_unique<jsonPropertiesDatabase>(
62  primclex, calc_type, location));
63  }
64  }
65 };
66 } // namespace
67 
69  DB::for_each_type(InsertImpl(db_handler));
70  if (db_handler.primclex().has_dir()) {
71  DB::for_each_config_type(InsertPropsImpl(db_handler));
72  }
73 }
74 
76  : m_dir(_root) {}
77 
78 template <typename DataObject>
80  return m_dir.casm_dir() / traits<jsonDB>::name /
81  (traits<DataObject>::short_name + "_list.json");
82 }
83 
84 template <typename DataObject>
85 fs::path jsonDB::DirectoryStructure::props_list(std::string calctype) const {
86  return m_dir.casm_dir() / traits<jsonDB>::name / _calctype(calctype) /
87  (traits<DataObject>::short_name + "_props.json");
88 }
89 
90 std::string jsonDB::DirectoryStructure::_calctype(std::string calctype) const {
91  return std::string("calctype.") + calctype;
92 }
93 
95  : Database<Supercell>(_primclex), m_is_open(false) {}
96 
98  if (m_is_open) {
99  return *this;
100  }
101 
102  if (primclex().has_dir()) {
103  jsonDB::DirectoryStructure dir(primclex().dir().root_dir());
104  if (fs::exists(dir.obj_list<Supercell>())) {
105  _read_scel_list();
106  } else if (fs::exists(primclex().dir().SCEL())) {
107  _read_SCEL();
108  }
109  }
110  master_selection() = Selection<Supercell>(*this);
111  this->read_aliases();
112 
113  m_is_open = true;
114  return *this;
115 }
116 
118  if (!primclex().has_dir()) {
119  throw std::runtime_error(
120  "Error in jsonDatabase<Supercell>::commit(): CASM project has no root "
121  "directory.");
122  }
123 
124  jsonParser json;
125  json["version"] = traits<jsonDB>::version;
126 
127  for (const auto &scel : *this) {
128  json["supercells"][scel.name()] = scel.transf_mat();
129  }
130 
131  jsonDB::DirectoryStructure dir(primclex().dir().root_dir());
132 
133  SafeOfstream file;
134  fs::create_directories(dir.obj_list<Supercell>().parent_path());
135  file.open(dir.obj_list<Supercell>());
136  json.print(file.ofstream());
137  file.close();
138 
139  this->write_aliases();
140  auto handler = primclex().settings().query_handler<Supercell>();
141  handler.set_selected(master_selection());
142  master_selection().write(
143  handler.dict(), primclex().dir().template master_selection<Supercell>(),
144  false, false);
145 }
146 
148  m_is_open = false;
149 
150  this->clear();
151 }
152 
154  if (!primclex().has_dir()) {
155  throw std::runtime_error(
156  "Error in jsonDatabase<Supercell>::_read_scel_list(): CASM project has "
157  "no root directory.");
158  }
159  jsonDB::DirectoryStructure dir(primclex().dir().root_dir());
160  jsonParser json(dir.obj_list<Supercell>());
161 
162  // check json version
163  if (!json.contains("version") ||
164  json["version"].get<std::string>() != traits<jsonDB>::version) {
165  throw std::runtime_error(
166  std::string("Error jsonDB version mismatch: found: ") +
167  json["version"].get<std::string>() +
168  " expected: " + traits<jsonDB>::version);
169  }
170 
171  if (!json.is_obj() || !json.contains("supercells")) {
172  throw std::runtime_error(std::string("Error invalid format: ") +
173  dir.obj_list<Supercell>().string());
174  }
175 
176  auto it = json["supercells"].begin();
177  auto end = json["supercells"].end();
178  for (; it != end; ++it) {
179  Eigen::Matrix3l mat;
180  from_json(mat, *it);
181  this->emplace(&primclex(), mat);
182  }
183 }
184 
186  if (!primclex().has_dir()) {
187  throw std::runtime_error(
188  "Error in jsonDatabase<Supercell>::_read_SCEL(): CASM project has no "
189  "root directory.");
190  }
191  // expect a file with format:
192  //
193  // Supercell Number: 0 Volume: 1
194  // Supercell Transformation Matrix:
195  // 1 0 0
196  // 0 1 0
197  // 0 0 1
198  //
199  // Supercell Number: 1 Volume: 2
200  // Supercell Transformation Matrix:
201  // 1 0 -1
202  // 0 1 0
203  // 0 0 2
204 
205  Eigen::Matrix3l mat;
206 
207  std::string s;
208  fs::ifstream stream(primclex().dir().SCEL());
209  while (!stream.eof()) {
210  std::getline(stream, s);
211  if (s[0] == 'S') {
212  std::getline(stream, s);
213  stream >> mat;
214 
215  this->emplace(&primclex(), mat);
216  }
217  }
218 }
219 
221  : Database<Configuration>(_primclex), m_is_open(false) {}
222 
224  if (m_is_open) {
225  return *this;
226  }
227 
228  if (!primclex().has_dir()) {
229  m_is_open = true;
230  master_selection() = Selection<Configuration>(*this);
231  return *this;
232  }
233 
234  jsonDB::DirectoryStructure dir(primclex().dir().root_dir());
235  fs::path config_list_path = dir.obj_list<Configuration>();
236 
237  if (!fs::exists(config_list_path)) {
238  m_is_open = true;
239  master_selection() = Selection<Configuration>(*this);
240  return *this;
241  }
242 
243  jsonParser json(config_list_path);
244 
245  if (!json.is_obj() || !json.contains("supercells")) {
246  throw std::runtime_error(std::string("Error invalid format: ") +
247  config_list_path.string());
248  }
249 
250  // check json version
251  if (!json.contains("version") ||
252  json["version"].get<std::string>() != traits<jsonDB>::version) {
253  throw std::runtime_error(
254  std::string("Error jsonDB version mismatch: found: ") +
255  json["version"].get<std::string>() +
256  " expected: " + traits<jsonDB>::version);
257  }
258 
259  // read config list contents
260  auto scel_it = json["supercells"].begin();
261  auto scel_end = json["supercells"].end();
262  bool is_new = false;
263 
264  for (; scel_it != scel_end; ++scel_it) {
265  auto config_it = scel_it->begin();
266  auto config_end = scel_it->end();
267 
268  const Supercell &scel = *primclex()
269  .db_handler()
271  .find(scel_it.name());
272 
273  for (; config_it != config_end; ++config_it) {
274  Configuration configuration{scel};
275  from_json(configuration.configdof(), (*config_it)["dof"]);
276 
277  auto source_it = config_it->find("source");
278  if (source_it != config_it->end()) {
279  configuration.set_source(*source_it);
280  }
281  auto cache_it = config_it->find("cache");
282  if (cache_it != config_it->end()) {
283  configuration.set_initial_cache(*cache_it);
284  }
285 
286  this->clear_name(configuration);
287  // config_it.name() is the JSON attribute name, which is the config ID
288  this->set_id(configuration, config_it.name());
289 
290  auto result = m_config_list.emplace(configuration);
291  _on_insert_or_emplace(result, is_new);
292  }
293  }
294 
295  // read next config id for each supercell
296  from_json(m_config_id, json["config_id"]);
297  master_selection() = Selection<Configuration>(*this);
298  this->read_aliases();
299 
300  m_is_open = true;
301  return *this;
302 }
303 
305  if (!m_is_open) {
306  throw std::runtime_error(
307  "Error in jsonDatabase<Configuration>::commit(): Database not open");
308  }
309  if (!primclex().has_dir()) {
310  throw std::runtime_error(
311  "Error in jsonDatabase<Configuration>::commit(): CASM project has no "
312  "root directory.");
313  }
314 
315  jsonDB::DirectoryStructure dir(primclex().dir().root_dir());
316  fs::path config_list_path = dir.obj_list<Configuration>();
317  if (primclex().db_handler().db<Supercell>(traits<jsonDB>::name).size() == 0) {
318  fs::remove(config_list_path);
319  return;
320  }
321 
322  jsonParser json;
323  if (fs::exists(config_list_path)) {
324  json.read(config_list_path);
325  } else {
326  json.put_obj();
327  }
328  json["version"] = traits<jsonDB>::version;
329 
330  json["supercells"] = jsonParser::object();
331  for (const auto &config : m_config_list) {
332  jsonParser &configjson =
333  json["supercells"][config.supercell().name()][config.id()];
334  to_json(config.configdof(), configjson["dof"]);
335  to_json(config.source(), configjson["source"]);
336  configjson["cache"].put_obj();
337  if (config.cache_updated()) {
338  to_json(config.cache(), configjson["cache"]);
339  }
340  }
341 
342  json["config_id"] = m_config_id;
343 
344  SafeOfstream file;
345  fs::create_directories(config_list_path.parent_path());
346  file.open(config_list_path);
347  int indent = 0;
348  int prec = 12;
349  json_spirit::write_stream((json_spirit::mValue &)json, file.ofstream(),
350  indent, prec);
351  file.close();
352 
353  this->write_aliases();
354  auto handler = primclex().settings().query_handler<Configuration>();
355  handler.set_selected(master_selection());
356 
357  bool write_json = false;
358  bool only_selected = false;
359  master_selection().write(
360  handler.dict(),
361  primclex().dir().template master_selection<Configuration>(), write_json,
362  only_selected);
363 }
364 
366  m_name_to_config.clear();
367  m_config_list.clear();
368  m_scel_range.clear();
369 
370  m_is_open = false;
371 }
372 
374  const {
375  return _iterator(m_config_list.begin());
376 }
377 
379  return _iterator(m_config_list.end());
380 }
381 
383  const {
384  return m_config_list.size();
385 }
386 
387 std::pair<jsonDatabase<Configuration>::iterator, bool>
389  auto result = m_config_list.insert(config);
390 
391  return _on_insert_or_emplace(result, true);
392 }
393 
394 std::pair<jsonDatabase<Configuration>::iterator, bool>
396  auto result = m_config_list.insert(std::move(config));
397 
398  return _on_insert_or_emplace(result, true);
399 }
400 
402  const Configuration &config) {
404  return insert(config).first;
405 }
406 
408  iterator pos) {
409  // get m_config_list iterator
410  auto base_it = static_cast<db_set_iterator *>(pos.get())->base();
411 
412  // erase name & alias
413  m_name_to_config.erase(base_it->name());
414  master_selection().data().erase(base_it->name());
415  // update scel_range
416  auto _scel_range_it = m_scel_range.find(base_it->supercell().name());
417  if (_scel_range_it->second.first == _scel_range_it->second.second) {
418  m_scel_range.erase(_scel_range_it);
419  } else if (_scel_range_it->second.first == base_it) {
420  ++(_scel_range_it->second.first);
421  } else if (_scel_range_it->second.second == base_it) {
422  --(_scel_range_it->second.second);
423  }
424 
425  // erase Configuration
426  return _iterator(m_config_list.erase(base_it));
427 }
428 
430  const std::string &name_or_alias) const {
431  auto it = m_name_to_config.find(this->name(name_or_alias));
432  if (it == m_name_to_config.end()) {
433  return _iterator(m_config_list.end());
434  }
435  return _iterator(it->second);
436 }
437 
441  auto it = m_scel_range.find(scelname);
442  if (it == m_scel_range.end()) {
443  return boost::make_iterator_range(end(), end());
444  } else {
445  auto &res = it->second;
446  return boost::make_iterator_range(_iterator(res.first),
447  _iterator(std::next(res.second)));
448  }
449 }
450 
458  // not clear if using m_scel_range to search on a sub-range would help...
459  auto res = m_config_list.find(config);
460  if (res == m_config_list.end()) {
461  return end();
462  }
463  return _iterator(res);
464 }
465 
468 std::pair<jsonDatabase<Configuration>::iterator, bool>
470  std::pair<base_iterator, bool> &result, bool is_new) {
471  if (result.second) {
472  const Configuration &config = *result.first;
473  assert(&config.primclex() == &primclex() &&
474  "jsonDatabase<Configuration>::_on_insert_or_emplace primclex does "
475  "not match");
476 
477  if (is_new) {
478  // set the config id, and increment
479  auto _config_id_it = m_config_id.find(config.supercell().name());
480  if (_config_id_it == m_config_id.end()) {
481  _config_id_it =
482  m_config_id.insert(std::make_pair(config.supercell().name(), 0))
483  .first;
484  }
485  this->set_id(config, _config_id_it->second++);
486  }
487 
488  // update name -> config
489  m_name_to_config.insert(std::make_pair(config.name(), result.first));
490 
491  // check if scel_range needs updating
492  auto _scel_range_it = m_scel_range.find(config.supercell().name());
493 
494  // new supercell
495  if (_scel_range_it == m_scel_range.end()) {
496  m_scel_range.emplace(config.supercell().name(),
497  std::make_pair(result.first, result.first));
498  }
499  // if new 'begin' of scel range
500  else if (_scel_range_it->second.first == std::next(result.first)) {
501  _scel_range_it->second.first = result.first;
502  }
503  // if new 'end' of scel range (!= past-the-last config in scel)
504  else if (_scel_range_it->second.second == std::prev(result.first)) {
505  _scel_range_it->second.second = result.first;
506  }
507 
508  master_selection().data().emplace(config.name(), 0);
509  }
510 
511  return std::make_pair(_iterator(result.first), result.second);
512 }
513 } // namespace DB
514 } // namespace CASM
515 
516 // explicit template instantiations
517 #define INST_jsonDB(r, data, type) \
518  template fs::path jsonDB::DirectoryStructure::obj_list<type>() const;
519 
520 #define INST_jsonDB_config(r, data, type) \
521  template fs::path jsonDB::DirectoryStructure::props_list<type>( \
522  std::string calctype) const;
523 
524 namespace CASM {
525 namespace DB {
526 
527 BOOST_PP_SEQ_FOR_EACH(INST_jsonDB, _, CASM_DB_TYPES)
528 BOOST_PP_SEQ_FOR_EACH(INST_jsonDB_config, _, CASM_DB_CONFIG_TYPES)
529 } // namespace DB
530 } // namespace CASM
std::set< std::string > & s
#define CASM_DB_TYPES
#define CASM_DB_CONFIG_TYPES
Provides access to all databases.
DatabaseIterator for implementations using std::set<ValueType>
virtual iterator erase(iterator pos)=0
std::string _calctype(std::string calctype) const
Definition: jsonDatabase.cc:90
fs::path props_list(std::string calctype) const
Definition: jsonDatabase.cc:85
DirectoryStructure(const fs::path _root)
Definition: jsonDatabase.cc:75
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
Represents a supercell of the primitive parent crystal structure.
Definition: Supercell.hh:51
static jsonParser object()
Returns an empty json object.
Definition: jsonParser.hh:395
iterator begin()
Returns const_iterator to beginning of JSON object or JSON array.
Definition: jsonParser.cc:497
bool contains(const std::string &name) const
Return true if JSON object contains 'name'.
Definition: jsonParser.cc:601
iterator end()
Returns iterator to end of JSON object or JSON array.
Definition: jsonParser.cc:520
bool read(std::istream &stream)
Reads json from the stream.
Definition: jsonParser.cc:168
jsonParser & put_obj()
Puts new empty JSON object.
Definition: jsonParser.hh:354
bool is_obj() const
Check if object type.
Definition: jsonParser.cc:272
void print(std::ostream &stream, unsigned int indent=2, unsigned int prec=12) const
Print json to stream.
Definition: jsonParser.cc:188
void commit(ProjectSettings const &set)
std::string scelname(const Structure &prim, const Lattice &superlat)
Make supercell name name [deprecated].
Definition: Supercell.cc:497
T get(Args &&... args) const
Get data from json, using one of several alternatives.
Definition: jsonParser.hh:716
const PrimClex & primclex
Definition: jsonDatabase.cc:52
const DirectoryStructure & dir
Definition: jsonDatabase.cc:53
#define INST_jsonDB_config(r, data, type)
#define INST_jsonDB(r, data, type)
jsonDB::DirectoryStructure json_dir
Definition: jsonDatabase.cc:54
DatabaseHandler & db_handler
Definition: jsonDatabase.cc:31
GenericDatumFormatter< std::string, ConfigEnumDataType > name()
GenericDatumFormatter< bool, ConfigEnumDataType > is_new()
ConfigIO::GenericConfigFormatter< jsonParser > config()
Definition: ConfigIO.cc:777
jsonParser & to_json(ImportSettings const &_set, jsonParser &_json)
Definition: Import.cc:10
jsonParser const & from_json(ImportSettings &_set, jsonParser const &_json)
Definition: Import.cc:18
void for_each_type(F f)
void for_each_config_type(F f)
Main CASM namespace.
Definition: APICommand.hh:8
const CELL_TYPE SCEL
Definition: enum.hh:30
GenericDatumFormatter< std::string, DataObject > name()
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
Matrix< long int, 3, 3 > Matrix3l
Definition: eigen.hh:12
pair_type calctype
Definition: settings.cc:143
static void insert(DatabaseHandler &)
Definition: jsonDatabase.cc:68
static const std::string version
Database format version, incremented separately from casm –version.
Definition: jsonDatabase.hh:27
static const std::string name
Definition: jsonDatabase.hh:24