CASM  1.1.0
A Clusters Approach to Statistical Mechanics
ConfigEnumInput_json_io.cc
Go to the documentation of this file.
2 
4 #include "casm/clex/ConfigDoF.hh"
5 #include "casm/clex/ScelEnum.hh"
16 
17 namespace CASM {
18 
20 jsonParser &to_json(ConfigEnumInput const &config_enum_input,
21  jsonParser &json) {
22  json["configuration"] = config_enum_input.configuration();
23  json["sites"] = config_enum_input.sites();
24  return json;
25 }
26 
29  const jsonParser &json,
30  std::shared_ptr<Structure const> const &shared_prim) {
31  jsonParser tjson{json};
33 
34  std::runtime_error error_if_invalid{
35  "Error reading ConfigEnumInput from JSON"};
36  report_and_throw_if_invalid(parser, CASM::log(), error_if_invalid);
37 
38  return *parser.value;
39 }
40 
43  std::shared_ptr<Structure const> const &shared_prim) {
44  auto configuration_ptr =
45  parser.require<Configuration>("configuration", shared_prim);
46  auto sites_ptr = parser.require<std::set<Index>>("sites");
47 
48  if (parser.valid()) {
49  parser.value =
50  notstd::make_unique<ConfigEnumInput>(*configuration_ptr, *sites_ptr);
51  }
52 }
53 
58 void from_json(
59  std::vector<std::pair<std::string, ConfigEnumInput>> &config_enum_input,
60  jsonParser const &json, std::shared_ptr<Structure const> shared_prim,
61  PrimClex const *primclex, DB::Database<Supercell> &supercell_db,
62  DB::Database<Configuration> &configuration_db) {
63  jsonParser tjson{json};
65  tjson, shared_prim, primclex, supercell_db, configuration_db};
66 
67  std::runtime_error error_if_invalid{
68  "Error reading std::vector<ConfigEnumInput> from JSON"};
69  report_and_throw_if_invalid(parser, CASM::log(), error_if_invalid);
70 }
71 
79  DB::Database<Supercell> &supercell_db) {
80  int min, max;
81  std::string dirs;
82  int default_min = 1;
83  std::string default_dirs{"abc"};
84  Eigen::Matrix3i generating_matrix;
85  Eigen::Matrix3i default_matrix{Eigen::Matrix3i::Identity()};
86 
87  parser.optional_else(min, "min", default_min);
88  parser.require(max, "max");
89  parser.optional_else(dirs, "dirs", default_dirs);
90 
91  // support "unit_cell" == supercell name
92  if (parser.self.contains("unit_cell") &&
93  parser.self["unit_cell"].is_string()) {
94  std::string scelname = parser.self["unit_cell"].get<std::string>();
95  auto supercell_it = supercell_db.find(scelname);
96  if (supercell_it == supercell_db.end()) {
97  std::stringstream msg;
98  msg << "Error parsing \"unit_cell\": string value not equal to any "
99  "existing supercell name";
100  parser.error.insert(msg.str());
101  } else {
102  generating_matrix =
103  supercell_it->sym_info().transformation_matrix_to_super().cast<int>();
104  }
105  } else {
106  parser.optional_else(generating_matrix, "unit_cell", default_matrix);
107  }
108 
109  if (parser.self.contains("existing_only")) {
110  std::stringstream msg;
111  msg << "The option \"existing_only\" is no longer supported. "
112  << "To select all existing supercells use \"supercell_selection\": "
113  "\"ALL\".";
114  parser.error.insert(msg.str());
115  }
116 
117  if (parser.valid()) {
118  parser.value = notstd::make_unique<xtal::ScelEnumProps>(min, max + 1, dirs,
119  generating_matrix);
120  }
121 }
122 
125  return " scelnames: array of strings (optional, override with --scelnames) "
126  " \n"
127  " Names of supercells used as input states. All sites will be set "
128  "to the first \n"
129  " listed occupant, and all other DoFs will be set to zero. Ex: "
130  " \n\n"
131 
132  " \"scelnames\": [\"SCEL1_1_1_1_0_0_0\", "
133  "\"SCEL2_2_1_1_0_0_0\"] \n\n"
134 
135  " supercell_selection: string (optional) "
136  " \n"
137  " Name of a selection of supercells to use as input states. "
138  " \n\n"
139 
140  " supercells: object, ScelEnum JSON settings (optional, override "
141  "with --min, --max) \n"
142  " Indicate supercells to use as input states in terms of size and "
143  "unit cell via \n"
144  " a JSON object conforming to the format of 'ScelEnum' JSON "
145  "settings \"min\", \n"
146  " \"max\", \"dirs\", and \"unit_cell\". See 'ScelEnum' description "
147  "for more \n"
148  " details. "
149  " \n\n"
150 
151  " confignames: array of strings (optional, override with "
152  "--confignames) \n"
153  " Names of configurations to be used as input states. All "
154  "specified sublattices or\n"
155  " sites will be enumerated on and all other DoFs will "
156  " \n"
157  " maintain the values of the initial state. Ex: "
158  " \n\n"
159 
160  " \"confignames\": [\"SCEL1_1_1_1_0_0_0/1\", "
161  "\"SCEL2_2_1_1_0_0_0/3\"] \n\n"
162 
163  " config_selection: string (optional) "
164  " \n"
165  " Name of a selection of configurations to use as initial states. "
166  " \n\n"
167 
168  " config_list: array (optional) "
169  " \n"
170  " Allows direct input of configurations that may not already exist "
171  "in the project \n"
172  " database via a JSON array of objects conforming to the "
173  "\"config.json\" format. \n"
174  " If the \"dof\" component is not included all sites will be set "
175  "to the first \n"
176  " listed occupant, and all other DoFs will be set to zero, as if "
177  "specifying a \n"
178  " a supercell. Ex: "
179  " \n\n"
180 
181  " \"configs\" : [ "
182  " \n"
183  " { "
184  " \n"
185  " \"transformation_matrix_to_supercell\": [ "
186  " \n"
187  " [ 0, -1, -1 ], "
188  " \n"
189  " [ 0, 1, -1 ], "
190  " \n"
191  " [ 1, 0, 1 ] "
192  " \n"
193  " ], "
194  " \n"
195  " \"identifier\": \"custom_strain.1\", "
196  " \n"
197  " \"dof\": { "
198  " \n"
199  " \"global_dofs\" : { "
200  " \n"
201  " \"Hstrain\" : { "
202  " \n"
203  " \"values\" : [ 0.100000000000, 0.100000000000, "
204  "0.100000000000, 0.000000000000, 0.000000000000, 0.000000000000 ]\n"
205  " } "
206  " \n"
207  " }, "
208  " \n"
209  " \"occ\" : [ 0, 0 ] "
210  " \n"
211  " } "
212  " \n"
213  " } "
214  " \n"
215  " ] "
216  " \n\n"
217 
218  " sublats: array of integers (optional, default none) "
219  " \n"
220  " Selects sites by specifying sublattices. Each sublattice index "
221  "corresponds to a \n"
222  " basis site in prim.json, indexed from 0. Ex: "
223  " \n\n"
224 
225  " \"sublats\" : [0, 2] "
226  " \n\n"
227 
228  " sites: array of 4-entry integer arrays (optional, default none) \n"
229  " Selects sites by [b,i,j,k] convention, where 'b' is sublattice "
230  "index and [i,j,k]\n"
231  " specifies linear combinations of primitive-cell lattice vectors. "
232  "Ex: \n\n"
233 
234  " \"sites\" : [[0,0,0,0], "
235  " \n"
236  " [2,0,0,0]] "
237  " \n\n"
238 
239  " cluster_specs: object (optional) "
240  " \n"
241  " JSON object specifying orbits of clusters to generate. Each "
242  "orbit prototype is \n"
243  " used to select sites on each input supercell or configuration. "
244  "If there are 4 \n"
245  " supercells or configurations selected, and there are 10 orbits "
246  "generated, then \n"
247  " there will be 4*10=40 initial states generated. The "
248  "\"cluster_specs\" option \n"
249  " cannot be used with the \"sublats\" or \"sites\" options. Expect "
250  "format is: \n\n"
251 
252  " method: string (required) "
253  " \n"
254  " Specify which cluster orbit generating method will be used. "
255  "Supported: \n\n"
256 
257  " - \"periodic_max_length\": Clusters differing by a lattice "
258  "translation are \n"
259  " considered equivalent. Cluster generation is truncated by "
260  "specifying the \n"
261  " maximum distance between sites in a cluster for 2-point, "
262  "3-point, etc. \n"
263  " clusters. The point clusters comprising the asymmetric unit "
264  "of the prim \n"
265  " structure are always included. After the cluster orbits are "
266  "generated using \n"
267  " the prim factor group symmetry, the orbits are broken into "
268  "sub-orbits \n"
269  " reflecting the configuration factor group symmetry of the "
270  "input state. Any \n"
271  " orbits that are duplicated under periodic boundary "
272  "conditions are removed. \n\n"
273 
274  " params: object (required) \n"
275  " Specifies parameters for the method selected by `method`. "
276  "Options depend on the \n"
277  " `method` chosen: \n\n"
278 
279  " For method==\"periodic_max_length\": \n"
280  " orbit_branch_specs: object (optional)\n"
281  " Cluster generation is truncated by specifying the maximum "
282  "distance\n"
283  " between sites in a cluster for each orbit branch (i.e. "
284  "2-point, 3-point, etc.\n"
285  " clusters). The 1-point clusters comprising the asymmetric "
286  "unit of the prim\n"
287  " structure are always included. \n\n"
288 
289  " Example: \n"
290  " \"orbit_branch_specs\": {\n"
291  " \"2\": { \"max_length\": 10.0 },\n"
292  " \"3\": { \"max_length\": 8.0 },\n"
293  " ...\n"
294  " }\n\n"
295 
296  " orbit_specs: array (optional) \n"
297  " An array of clusters which are used to generate and "
298  "include orbits of clusters \n"
299  " whether or not they meet the `max_length` truncation "
300  "criteria. See the \n"
301  " cluster input format below. Use the "
302  "\"include_subclusters\" option to force \n"
303  " generation of orbits for all subclusters of the specified "
304  "cluster. \n"
305 
306  " Example cluster, with \"Direct\" coordinates: \n"
307  " { \n"
308  " \"coordinate_mode\" : \"Direct\", \n"
309  " \"sites\" : [ \n"
310  " [ 0.000000000000, 0.000000000000, 0.000000000000 "
311  "], \n"
312  " [ 1.000000000000, 0.000000000000, 0.000000000000 "
313  "], \n"
314  " [ 2.000000000000, 0.000000000000, 0.000000000000 "
315  "], \n"
316  " [ 3.000000000000, 0.000000000000, 0.000000000000 "
317  "]], \n"
318  " \"include_subclusters\" : true \n"
319  " } \n\n"
320 
321  " Example cluster, with \"Integral\" coordinates: \n"
322  " { \n"
323  " \"coordinate_mode\" : \"Integral\", \n"
324  " \"sites\" : [ \n"
325  " [ 0, 0, 0, 0 ], \n"
326  " [ 0, 1, 0, 0 ], \n"
327  " [ 1, 0, 0, 0 ]], \n"
328  " \"include_subclusters\" : true \n"
329  " } \n\n";
330 }
331 
409 void parse(
410  InputParser<std::vector<std::pair<std::string, ConfigEnumInput>>> &parser,
411  std::shared_ptr<Structure const> shared_prim, PrimClex const *primclex,
412  DB::Database<Supercell> &supercell_db,
413  DB::Database<Configuration> &configuration_db) {
414  // check for "config_selection" and "confignames"
415  DB::Selection<Configuration> config_selection;
416  try {
417  config_selection = DB::make_selection<Configuration>(
418  configuration_db, parser.self, "confignames", "config_selection");
419  } catch (std::exception &e) {
420  std::stringstream msg;
421  msg << "Error creating input states from configurations: " << e.what();
422  parser.error.insert(msg.str());
423  }
424 
425  // make_and_insert_canonical_supercell
426 
427  // option 1: create and use possibly non-canonical standalone supercell
428  // (default) option 2: make_and_insert_canonical_supercell: bool (optional,
429  // default = false)
430  // - make & insert canonical supercell, do not insert configuration
431  // option 3: make_and_insert_canonical_configuration: true (optional, default
432  // = false)
433  // - make & insert canonical supercell, and insert configuration
434 
435  // check for "config_list"
436  typedef std::vector<std::pair<std::string, Configuration>> NamedConfiguration;
437  NamedConfiguration config_list;
438 
439  if (parser.self.contains("config_list")) {
440  try {
441  auto it = parser.self.find("config_list");
442  auto end = parser.self.end();
443  for (; it != end; ++it) {
444  auto config_ptr = it->make<Configuration>(shared_prim);
445  std::string identifier =
446  it->get_if_else("identifier", config_ptr->name());
447  config_list.emplace_back(identifier, std::move(*config_ptr));
448  }
449  } catch (std::exception &e) {
450  std::stringstream msg;
451  msg << "Error creating input states from config_list: " << e.what();
452  parser.error.insert(msg.str());
453  }
454  }
455 
456  // check for "supercell_selection" and "scelnames"
457  DB::Selection<Supercell> supercell_selection;
458  try {
459  supercell_selection = DB::make_selection<Supercell>(
460  supercell_db, parser.self, "scelnames", "supercell_selection");
461  } catch (std::exception &e) {
462  std::stringstream msg;
463  msg << "Error creating input states from supercells: " << e.what();
464  parser.error.insert(msg.str());
465  }
466 
467  // check for "supercells"
468  auto scel_enum_props_subparser =
469  parser.subparse_if<xtal::ScelEnumProps>("supercells", supercell_db);
470 
471  // check for "sublats"
472  std::vector<Index> sublats;
473  parser.optional(sublats, "sublats");
474  for (Index b : sublats) {
475  if (b < 0 || b >= shared_prim->basis().size()) {
476  std::stringstream msg;
477  msg << "Error reading sublats: value out of range [0, "
478  << shared_prim->basis().size() << ")";
479  parser.error.insert(msg.str());
480  }
481  }
482 
483  // check for "sites"
484  std::vector<UnitCellCoord> sites;
485  parser.optional(sites, "sites");
486  Index i = 0;
487  for (UnitCellCoord site_uccoord : sites) {
488  Index b = site_uccoord.sublattice();
489  if (b < 0 || b >= shared_prim->basis().size()) {
490  std::stringstream msg;
491  msg << "Error reading sites[" << i
492  << "]: sublattice index out of range [0, "
493  << shared_prim->basis().size() << ")";
494  parser.error.insert(msg.str());
495  }
496  ++i;
497  }
498 
499  // Do not allow "cluster_specs" with "sublats" or "sites"
500  // (when would this be useful? which order to apply?)
501  if ((sublats.size() || sites.size()) &&
502  parser.self.contains("cluster_specs")) {
503  std::stringstream msg;
504  msg << "Error creating input states: "
505  << "cannot include \"cluster_specs\" with \"sublats\" or \"sites\"";
506  parser.error.insert(msg.str());
507  }
508 
509  // check for "cluster_specs"
510  auto cluster_specs_subparser = parser.subparse_if<ClusterSpecs>(
511  "cluster_specs", shared_prim, shared_prim->factor_group());
512  if (cluster_specs_subparser->value) {
513  if (cluster_specs_subparser->value->periodicity_type() !=
515  std::stringstream msg;
516  msg << "Error creating input states: "
517  << "\"cluster_specs\" method must be \"periodic_max_length\"";
518  cluster_specs_subparser->error.insert(msg.str());
519  }
520  }
521 
522  // at this point we have parsed everything except "cluster_specs",
523  // which is parsed later for each ConfigEnumInput
524  if (!parser.valid()) {
525  return;
526  }
527 
528  // Use the supercells and configurations input to construct ConfigEnumInput,
529  // by default these have all sites selected
530  std::vector<std::pair<std::string, ConfigEnumInput>> config_enum_input;
531  for (const auto &config : config_selection.selected()) {
532  config_enum_input.emplace_back(config.name(), config);
533  }
534  for (const auto &named_config : config_list) {
535  config_enum_input.emplace_back(named_config.first, named_config.second);
536  }
537  for (const auto &scel : supercell_selection.selected()) {
538  config_enum_input.emplace_back(scel.name(), scel);
539  }
540  if (scel_enum_props_subparser->value) {
541  ScelEnumByProps enumerator{shared_prim, *scel_enum_props_subparser->value};
542  for (auto const &supercell : enumerator) {
543  auto supercell_it = supercell_db.insert(supercell).first;
544  config_enum_input.emplace_back(supercell_it->name(), *supercell_it);
545  }
546  }
547 
548  // select sublattices and individual sites
549  if (sublats.size() || sites.size()) {
550  for (auto &input_name_value_pair : config_enum_input) {
551  // select sublats & sites, and modify name with sublats & sites
552  input_name_value_pair.second.clear_sites();
553 
554  std::stringstream ss;
555  if (sublats.size()) {
556  ss << ", sublats=" << jsonParser{sublats};
557  input_name_value_pair.second.select_sublattices(sublats);
558  }
559  if (sites.size()) {
560  ss << ", sites=" << jsonParser{sites};
561  input_name_value_pair.second.select_sites(sites);
562  }
563  input_name_value_pair.first += ss.str();
564  }
565  }
566 
567  // select clusters
568  if (cluster_specs_subparser->value != nullptr) {
569  // generate orbits from cluster_specs
570  auto orbits =
571  cluster_specs_subparser->value->make_periodic_orbits(CASM::log());
572 
573  // this will generate more ConfigEnumInput, with cluster sites selected
574  std::vector<std::pair<std::string, ConfigEnumInput>> all_with_cluster_sites;
575  for (auto &input_name_value_pair : config_enum_input) {
576  std::vector<ConfigEnumInput> with_cluster_sites;
577  select_cluster_sites(input_name_value_pair.second, orbits,
578  std::back_inserter(with_cluster_sites));
579 
580  // modify name with cluster site indices
581  for (auto const &value : with_cluster_sites) {
582  std::stringstream ss;
583  ss << ", cluster_sites=" << jsonParser{value.sites()};
584  std::string name = input_name_value_pair.first + ss.str();
585  all_with_cluster_sites.emplace_back(name, value);
586  }
587  }
588  config_enum_input = std::move(all_with_cluster_sites);
589  }
590 
591  // Move all constructed ConfigEnumInput into the parser.value
592  parser.value =
593  notstd::make_unique<std::vector<std::pair<std::string, ConfigEnumInput>>>(
594  std::move(config_enum_input));
595 
596  if (parser.value->size() == 0) {
597  std::stringstream msg;
598  msg << "Error creating input states: No supercells or configurations.";
599  parser.error.insert(msg.str());
600  }
601 }
602 
603 } // namespace CASM
std::shared_ptr< Structure const > shared_prim
iterator end() const override
Definition: ScelDatabase.cc:10
iterator find(const std::string &name_or_alias) const override
Definition: ScelDatabase.cc:36
RequiredType optional_else(fs::path option, const RequiredType &_default, Args &&... args)
std::unique_ptr< RequiredType > require(fs::path option, Args &&... args)
std::unique_ptr< T > value
Definition: InputParser.hh:234
PrimClex is the top-level data structure for a CASM project.
Definition: PrimClex.hh:55
bool is_string() const
Check if string.
Definition: jsonParser.cc:269
bool contains(const std::string &name) const
Return true if JSON object contains 'name'.
Definition: jsonParser.cc:601
std::set< Index > const & sites() const
Configuration const & configuration() const
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
ConfigIO::GenericConfigFormatter< jsonParser > config()
Definition: ConfigIO.cc:777
IdentitySymRepBuilder Identity()
Main CASM namespace.
Definition: APICommand.hh:8
jsonParser & to_json(const ClexDescription &desc, jsonParser &json)
Log & log()
Definition: Log.hh:424
Inserter select_cluster_sites(ConfigEnumInput const &reference_config_enum_input, std::vector< PrimPeriodicIntegralClusterOrbit > const &orbits, Inserter result)
GenericDatumFormatter< std::string, DataObject > name()
void from_json(ClexDescription &desc, const jsonParser &json)
T min(const T &A, const T &B)
Definition: CASM_math.hh:88
std::string parse_ConfigEnumInput_desc()
A string describing the JSON format for parsing named ConfigEnumInput.
void report_and_throw_if_invalid(KwargsParser const &parser, Log &log, ErrorType error)
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
void parse(InputParser< ConfigEnumOptions > &parser, std::string method_name, PrimClex const &primclex, DataFormatterDictionary< Configuration > const &dict)
T max(const T &A, const T &B)
Definition: CASM_math.hh:95
PrimClex * primclex
Definition: settings.cc:135
bool valid() const
Return true if this and and all subparsers are valid.
Definition: InputParser.cc:56
jsonParser const & self
Definition: InputParser.hh:81
std::set< std::string > error
Definition: Validator.hh:11
static ReturnType from_json(const jsonParser &json)
Default from_json is equivalent to.
Definition: jsonParser.hh:551