CASM  1.1.0
A Clusters Approach to Statistical Mechanics
SimpleStructureIO.cc
Go to the documentation of this file.
2 
8 #include "casm/global/errors.hh"
9 
10 namespace {
11 using namespace CASM;
12 
52 
53 static void _from_json_legacy(xtal::SimpleStructure &simple_structure,
54  const jsonParser &json) {
55  try {
56  COORD_TYPE coordinate_mode = json["coord_mode"].get<COORD_TYPE>();
57  simple_structure.lat_column_mat =
58  json["relaxed_lattice"].get<Eigen::Matrix3d>().transpose();
59 
60  // Input coordinate type to cartesian coordinate transformation matrix:
61  // cart_coord = coord_to_cart_mat * input_type_coord
62  Eigen::Matrix3d to_cartesian_matrix = Eigen::Matrix3d::Identity();
63  if (coordinate_mode == FRAC) {
64  to_cartesian_matrix = simple_structure.lat_column_mat;
65  }
66 
67  if (json.contains("relaxed_energy")) {
68  simple_structure.properties["energy"] =
69  json["relaxed_energy"].get<Eigen::MatrixXd>();
70  }
71  if (json.contains("relaxed_forces")) {
72  simple_structure.atom_info.properties["force"] =
73  json["relaxed_forces"].get<Eigen::MatrixXd>().transpose();
74  }
75  // note: silently ignoring legacy "relaxed_mag_basis" & "relaxed_magmom"
76 
77  // Read atom types
78  std::vector<Index> atoms_per_type =
79  json["atoms_per_type"].get<std::vector<Index> >();
80  std::vector<std::string> atom_type =
81  json["atom_type"].get<std::vector<std::string> >();
82  for (Index i = 0; i < atoms_per_type.size(); ++i) {
83  for (Index j = 0; j < atoms_per_type[i]; ++j) {
84  simple_structure.atom_info.names.push_back(atom_type[i]);
85  }
86  }
87 
88  // Read basis coordinates
89  simple_structure.atom_info.coords =
90  to_cartesian_matrix *
91  json["relaxed_basis"].get<Eigen::MatrixXd>().transpose();
92 
93  } catch (const std::exception &ex) {
94  std::stringstream ss;
95  ss << "Error parsing SimpleStructure from (legacy) JSON object. "
96  << "One or more tags were improperly specified:\n"
97  << ex.what();
98  throw libcasm_runtime_error(ss.str());
99  }
100  return;
101 }
102 
107 static jsonParser &_types_to_json(std::vector<std::string> const &names,
108  jsonParser &json, std::string field_name,
109  std::set<std::string> const &excluded_species,
110  std::vector<Index> &permute) {
111  jsonParser &names_json = json[field_name].put_array();
112  for (Index i = 0; i < names.size(); ++i) {
113  if (excluded_species.count(names[i])) continue;
114  names_json.push_back(names[i]);
115  permute.push_back(i);
116  }
117  return json;
118 }
119 
124 static jsonParser &_coords_to_json(
125  Eigen::MatrixXd const &coords, jsonParser &json, std::string field_name,
126  std::vector<Index> const &permute,
127  Eigen::Matrix3d const &to_coord_mode_matrix) {
128  jsonParser &tjson = json[field_name].put_array();
129  for (Index i : permute) {
130  tjson.push_back(to_coord_mode_matrix * coords.col(i),
132  }
133  return json;
134 }
135 
140 static jsonParser &_properties_to_json(
141  std::map<std::string, Eigen::MatrixXd> const &properties, jsonParser &json,
142  std::string field_name, std::vector<Index> const &permute) {
143  for (auto const &dof : properties) {
144  jsonParser &tjson = json[field_name][dof.first]["value"].put_array();
145  for (Index i : permute) {
146  tjson.push_back(dof.second.col(i), jsonParser::as_array());
147  }
148  }
149  return json;
150 }
151 
153 static void _types_from_json(std::vector<std::string> &names,
154  jsonParser const &json, std::string field_name) {
155  if (json.contains(field_name)) {
156  from_json(names, json[field_name]);
157  }
158 }
159 
161 static void _coords_from_json(Eigen::MatrixXd &coords, jsonParser const &json,
162  std::string field_name,
163  Eigen::Matrix3d const &to_cartesian_matrix) {
164  if (json.contains(field_name)) {
165  coords = to_cartesian_matrix *
166  json[field_name].get<Eigen::MatrixXd>().transpose();
167  }
168 }
169 
171 static void _properties_from_json(
172  std::map<std::string, Eigen::MatrixXd> &properties, jsonParser const &json,
173  std::set<std::string> allowed_field_names) {
174  for (std::string const &field : allowed_field_names) {
175  auto it = json.find(field);
176  if (it != json.end()) {
177  for (auto it2 = it->begin(); it2 != it->end(); ++it2) {
178  properties[it2.name()] =
179  (*it2)["value"].get<Eigen::MatrixXd>().transpose();
180  }
181  }
182  }
183 }
184 
192 static void _from_json_current(xtal::SimpleStructure &simple_structure,
193  const jsonParser &json) {
194  COORD_TYPE coordinate_mode = json["coord_mode"].get<COORD_TYPE>();
195  simple_structure.lat_column_mat =
196  json["lattice"].get<Eigen::Matrix3d>().transpose();
197 
198  // Input coordinate mode to cartesian coordinate transformation matrix:
199  // cart_coord = to_cartesian_matrix * input_mode_coord
200  Eigen::Matrix3d to_cartesian_matrix;
201  to_cartesian_matrix.setIdentity();
202  if (coordinate_mode == FRAC) {
203  to_cartesian_matrix = simple_structure.lat_column_mat;
204  }
205 
206  // Read global properties (if exists)
207  ::_properties_from_json(simple_structure.properties, json,
208  {"global_dofs", "global_vals"});
209 
210  // Read atom_info (if exists)
211  auto &atom_info = simple_structure.atom_info;
212  ::_types_from_json(atom_info.names, json, "atom_type");
213  ::_coords_from_json(atom_info.coords, json, "atom_coords",
214  to_cartesian_matrix);
215  ::_properties_from_json(atom_info.properties, json,
216  {"atom_dofs", "atom_vals"});
217 
218  // Read mol_info (if exists)
219  auto &mol_info = simple_structure.mol_info;
220  ::_types_from_json(mol_info.names, json, "mol_type");
221  ::_coords_from_json(mol_info.coords, json, "mol_coords", to_cartesian_matrix);
222  ::_properties_from_json(mol_info.properties, json, {"mol_dofs", "mol_vals"});
223 }
224 
228 static void _check_sizes(xtal::SimpleStructure::Info const &info,
229  std::string info_type) {
230  if (info.names.size() != info.coords.cols()) {
231  std::stringstream ss;
232  ss << info_type << ".coords.cols(): " << info.coords.cols()
233  << " != " << info_type << ".names.size(): " << info.names.size();
234  throw libcasm_runtime_error(ss.str());
235  }
236  // Check consistency of <atom/mol>_info.names and properties size
237  for (auto const &property_pair : info.properties) {
238  if (info.names.size() != property_pair.second.cols()) {
239  std::stringstream ss;
240  ss << info_type << ".properties[" << property_pair.first
241  << "\"].cols(): " << property_pair.second.cols() << " != " << info_type
242  << ".names.size(): " << info.names.size();
243  throw libcasm_runtime_error(ss.str());
244  }
245  }
246 }
247 
248 } // namespace
249 
250 namespace CASM {
251 
325 jsonParser &to_json(xtal::SimpleStructure const &simple_structure,
326  jsonParser &json,
327  std::set<std::string> const &excluded_species,
328  COORD_TYPE coordinate_mode) {
329  // Matrix to transform Cartesian coordinates to 'coordinate_mode' coordinates
330  Eigen::Matrix3d to_coord_mode_matrix = Eigen::Matrix3d::Identity();
331  if (coordinate_mode == FRAC) {
332  json["coord_mode"] = "Direct";
333  to_coord_mode_matrix = simple_structure.lat_column_mat.inverse();
334  } else {
335  json["coord_mode"] = "Cartesian";
336  }
337 
338  json["lattice"] = simple_structure.lat_column_mat.transpose();
339 
340  // Output global properties
341  for (auto const &dof : simple_structure.properties) {
342  to_json_array(dof.second, json["global_dofs"][dof.first]["value"]);
343  }
344 
345  // Note: _types_to_json checks excluded_species and populates
346  // "atom/mol_permute" with indices of
347  // sites that are included. This is used to only output the coordinates and
348  // properties of the correct sites in _properties_to_json and
349  // _coords_to_json
350 
351  // Output mol_info
352  auto const &atom_info = simple_structure.atom_info;
353  std::vector<Index> atom_permute;
354  ::_types_to_json(atom_info.names, json, "atom_type", excluded_species,
355  atom_permute);
356  ::_coords_to_json(atom_info.coords, json, "atom_coords", atom_permute,
357  to_coord_mode_matrix);
358  ::_properties_to_json(atom_info.properties, json, "atom_dofs", atom_permute);
359 
360  // Output mol_info
361  auto const &mol_info = simple_structure.mol_info;
362  std::vector<Index> mol_permute;
363  ::_types_to_json(atom_info.names, json, "mol_type", excluded_species,
364  mol_permute);
365  ::_coords_to_json(mol_info.coords, json, "mol_coords", mol_permute,
366  to_coord_mode_matrix);
367  ::_properties_to_json(mol_info.properties, json, "mol_dofs", mol_permute);
368 
369  return json;
370 }
371 
372 //***************************************************************************
373 
387 void from_json(xtal::SimpleStructure &simple_structure,
388  const jsonParser &json) {
389  try {
390  // For backwards read compatibility:
391  if (json.contains("atoms_per_type")) {
392  ::_from_json_legacy(simple_structure, json);
393  } else {
394  ::_from_json_current(simple_structure, json);
395  }
396 
397  // Check consistency of <atom/mol>_info.names and coords and properties size
398  ::_check_sizes(simple_structure.atom_info, "atom_info");
399  ::_check_sizes(simple_structure.mol_info, "mol_info");
400 
401  } catch (const std::exception &ex) {
402  std::stringstream ss;
403  ss << "Error parsing SimpleStructure from JSON object. "
404  << "One or more tags were improperly specified:\n"
405  << ex.what();
406  throw std::runtime_error(ss.str());
407  }
408 }
409 } // namespace CASM
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
iterator find(const std::string &name)
Return iterator to JSON object value with 'name'.
Definition: jsonParser.cc:543
jsonParser & put_array()
Puts new empty JSON array.
Definition: jsonParser.hh:362
Representation of a crystal of molecular and/or atomic occupants, and any additional properties....
std::map< std::string, Eigen::MatrixXd > properties
CASM::jsonParser & to_json_array(const Eigen::MatrixBase< Derived > &value, CASM::jsonParser &json)
Write Eigen Matrix with 1 row or 1 column to JSON array.
Definition: json_io.hh:313
jsonParser & push_back(const T &value, Args &&... args)
Definition: jsonParser.hh:684
T get(Args &&... args) const
Get data from json, using one of several alternatives.
Definition: jsonParser.hh:716
ConfigIO::GenericConfigFormatter< jsonParser > properties()
Definition: ConfigIO.cc:785
IdentitySymRepBuilder Identity()
Main CASM namespace.
Definition: APICommand.hh:8
Eigen::MatrixXd MatrixXd
jsonParser & to_json(const ClexDescription &desc, jsonParser &json)
COORD_TYPE
Definition: enum.hh:6
Eigen::Matrix3d Matrix3d
const COORD_TYPE FRAC
Definition: enum.hh:8
void from_json(ClexDescription &desc, const jsonParser &json)
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
Struct to encode all information about the crystal basis Info may describe the basis in a atomic cont...
Eigen::MatrixXd coords
(3 x names.size()) matrix of coordinates. coords.col(i) is Cartesian coordinate of site 'i'
std::vector< std::string > names
names[i] is name of species that occupies sites 'i'
std::map< std::string, Eigen::MatrixXd > properties
map of [property name, (m x names.size()) matrix] for all numerical site properties properties are as...