CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
ref.cc
Go to the documentation of this file.
3 #include "casm/clex/PrimClex.hh"
4 #include "casm/app/AppIO.hh"
6 
7 namespace CASM {
8 
9  namespace ref_impl {
10 
11  int initialize_global(fs::path chem_ref_path, const PrimClex &primclex, const jsonParser &json_ref, double lin_alg_tol) {
12 
14  json["chemical_reference"]["global"] = json_ref;
15 
16  ChemicalReference chem_ref = read_chemical_reference(json, primclex.get_prim(), lin_alg_tol);
17 
18  primclex.log() << "Initializing the chemical reference to: \n\n";
19  ChemicalReferencePrinter p(primclex.log(), chem_ref);
20  p.print_all();
21  write_chemical_reference(chem_ref, chem_ref_path);
22  return 0;
23  }
24 
25  int update_global(fs::path chem_ref_path, const PrimClex &primclex, const jsonParser &json_ref, double lin_alg_tol) {
26 
27  ChemicalReference chem_ref =
28  read_chemical_reference(chem_ref_path, primclex.get_prim(), lin_alg_tol);
29 
30  auto input = one_chemical_reference_from_json(primclex.get_prim(), json_ref);
31 
32  if(input.second.empty()) {
33  chem_ref.set_global(input.first);
34  }
35  else {
36  chem_ref.set_global(input.second.begin(), input.second.end(), lin_alg_tol);
37  }
38 
39  primclex.log() << "Updating the project-wide chemical reference to: \n";
40  ChemicalReferencePrinter p(primclex.log(), chem_ref);
41  p.print_global();
42  write_chemical_reference(chem_ref, chem_ref_path);
43  return 0;
44  }
45 
46  int update_config(std::string configname,
47  fs::path chem_ref_path,
48  const PrimClex &primclex,
49  const jsonParser &json_ref,
50  double lin_alg_tol) {
51 
52  if(!fs::exists(chem_ref_path)) {
53  primclex.err_log() << "Error using 'casm ref --set --configname': No reference found.\n";
54  primclex.err_log() << " Expected file at: " << chem_ref_path << "\n";
55  primclex.err_log() << "Use 'casm ref --set' or 'casm ref --set-auto' to set a project-wide reference first.\n";
57  }
58 
59  ChemicalReference chem_ref = read_chemical_reference(chem_ref_path, primclex.get_prim(), lin_alg_tol);
60 
61  try {
62  const Configuration &config = primclex.configuration(configname);
63  (void) config;
64  }
65  catch(...) {
66  primclex.err_log() << "Error using 'casm ref --set --configname': \n"
67  " Could not find configuration with name: " << configname << "\n";
68  return ERR_INVALID_ARG;
69  }
70 
71  auto input = one_chemical_reference_from_json(primclex.get_prim(), json_ref);
72  if(input.second.empty()) {
73  chem_ref.set_config(configname, input.first);
74  }
75  else {
76  chem_ref.set_config(configname, input.second.begin(), input.second.end(), lin_alg_tol);
77  }
78 
79  primclex.log() << "Updating the " << configname << " specialized reference to: \n";
80  ChemicalReferencePrinter p(primclex.log(), chem_ref);
81  p.print_config(configname);
82  write_chemical_reference(chem_ref, chem_ref_path);
83  return 0;
84 
85  }
86 
87  int update_supercell(std::string scelname,
88  fs::path chem_ref_path,
89  const PrimClex &primclex,
90  const jsonParser &json_ref,
91  double lin_alg_tol) {
92 
93  if(!fs::exists(chem_ref_path)) {
94  primclex.err_log() << "Error using 'casm ref --set --scelname': No reference found.\n";
95  primclex.err_log() << " Expected file at: " << chem_ref_path << "\n";
96  primclex.err_log() << "Use 'casm ref --set' or 'casm ref --set-auto' to set a project-wide reference first.\n";
98  }
99 
100  ChemicalReference chem_ref = read_chemical_reference(chem_ref_path, primclex.get_prim(), lin_alg_tol);
101 
102  try {
103  const Supercell &scel = primclex.get_supercell(scelname);
104  (void) scel;
105  }
106  catch(...) {
107  primclex.err_log() << "Error using 'casm ref --set --scelname': \n"
108  " Could not find supercell with name: " << scelname << "\n";
109  return ERR_INVALID_ARG;
110  }
111 
112  auto input = one_chemical_reference_from_json(primclex.get_prim(), json_ref);
113  if(input.second.empty()) {
114  chem_ref.set_supercell(scelname, input.first);
115  }
116  else {
117  chem_ref.set_supercell(scelname, input.second.begin(), input.second.end(), lin_alg_tol);
118  }
119 
120  primclex.log() << "Updating the " << scelname << " specialized reference to: \n";
121  ChemicalReferencePrinter p(primclex.log(), chem_ref);
122  p.print_supercell(scelname);
123  write_chemical_reference(chem_ref, chem_ref_path);
124  return 0;
125 
126  }
127 
128  }
129 
130  namespace Completer {
132 
133  const std::string &RefOption::set_str() const {
134  return m_set_str;
135  }
136 
141 
142  m_desc.add_options()
143  //("composition-space", "Display information on current composition space")
144  ("display,d", "Display current reference states")
145  ("set-auto", "Automatically set project level reference states using DFT results")
146  ("set", po::value<std::string>(&m_set_str),
147  "Set reference states using user specified compositions and energies "
148  "(Default: set project-wide references). \n"
149  "See examples below for the form of expected input.")
150  ("erase", "Erase reference states (Default: clear project-wide references).")
151  ("clex", po::value<std::string>(), "Name of the cluster expansion using the reference");
152 
153  return;
154  }
155  }
156 
157  // ///////////////////////////////////////
158  // 'ref' function for casm
159  // (add an 'if-else' statement in casm.cpp to call this)
160 
161  int ref_command(const CommandArgs &args) {
162 
163  po::variables_map vm;
164  std::string scelname, configname, set_str;
165  std::string species_order_string = "\n\n";
166 
167  const fs::path &root = args.root;
168  if(!root.empty()) {
169  std::stringstream ss;
170  DirectoryStructure dir(root);
171  Structure prim(read_prim(dir.prim()));
172 
173  ss << " For this project, the expected order is:\n"
174  << " '[";
175  auto names = prim.get_struc_molecule_name();
176  for(int i = 0; i < names.size(); i++) {
177  ss << names[i];
178  if(i != names.size() - 1) {
179  ss << ", ";
180  }
181  }
182  ss << "]'\n\n";
183 
184  species_order_string = ss.str();
185  }
186 
187 
188  Completer::RefOption ref_opt;
189 
190  try {
191  po::store(po::parse_command_line(args.argc, args.argv, ref_opt.desc()), vm);
192 
193  bool call_help = false;
194 
195  //quit out if there are no arguments
196  if(!vm.count("help") && !vm.count("desc")) {
197  if(vm.count("set") + vm.count("display") + vm.count("erase") + vm.count("set-auto") != 1) {
198  args.log << "Error in 'casm ref'. Please select one of --display, \n";
199  args.log << "--set, --set-auto, or --erase to use this option." << std::endl;
200 
201  call_help = true;
202  }
203 
204  if(vm.count("set")) {
205  if(vm.count("scelname") + vm.count("configname") > 1) {
206  args.err_log << "Error in 'casm ref --set'. Please select only one of --scelname, --configname \n";
207 
208  call_help = true;
209  }
210  }
211 
212  if(vm.count("erase")) {
213  if(vm.count("scelname") + vm.count("configname") > 1) {
214  args.err_log << "Error in 'casm ref --erase'. Please select only one of --scelname, --configname \n";
215 
216  call_help = true;
217  }
218  }
219  }
220 
223  if(vm.count("help") || call_help) {
224  args.log << std::endl;
225  args.log << ref_opt.desc() << std::endl;
226 
227  return 0;
228  }
229 
230  if(vm.count("desc")) {
231  args.log << "\n";
232  args.log << ref_opt.desc() << std::endl;
233 
234  args.log << "DESCRIPTION" << std::endl;
235  args.log << " The chemical reference determines the value of the formation energy \n"
236  " and chemical potentials calculated by CASM. \n\n"
237 
238  " Chemical references states are set by specifying a hyperplane in \n"
239  " energy/atom - composition (as atom_frac) space. This may be done by \n"
240  " specifying the hyperplane explicitly, or by specifying several \n"
241  " reference states with energy/atom and composition (as atom_frac) for \n"
242  " enough states to span the composition space of the allowed occupants \n"
243  " specified in the prim. For consistency with other CASM projects, \n"
244  " additional reference states extending to other compositional \n"
245  " dimensions may be included also. The pure Va reference is always 0. \n\n";
246 
247  args.log << " The input to '--set' can be one of three forms: \n\n"
248 
249  " 1) Input the energy_per_species for pure states: \n" <<
250  R"( '{"A": X, "B": X, "C": X}')" << "\n\n" <<
251 
252  " 2) Input reference state composition and energy_per_species: \n" <<
253  R"( '[)" << "\n" <<
254  R"( {"A": 3.4, "C": 2.0, "energy_per_species": 2.0},)" << "\n" <<
255  R"( {"B": 2.0, "energy_per_species": 4.0}, )" << "\n" <<
256  R"( {"C": 1.0, "energy_per_species": 3.0} )" << "\n" <<
257  R"( ]')" << "\n\n" <<
258 
259  " 3) Input an array of energy_per_species, for each species in prim, \n"
260  " including 0.0 for vacancy: \n"
261  " '[X, X, X]' \n"
262  << species_order_string;
263 
264  args.log << " When using '--set' it is also possible to specialize the chemical \n"
265  " reference at the supercell or configuration level by adding the \n"
266  " --scelname or --configname option. \n\n";
267 
268 
269 
270  args.log << " Examples:\n";
271  //args.log << " casm ref --composition-space \n";
272  //args.log << " - Print composition space column matrix of the primitive\n";
273  //args.log << " - Print null space column matrix\n";
274  //args.log << "\n";
275  args.log << " casm ref --display \n";
276  args.log << " - Print chemical reference\n";
277  args.log << "\n";
278  args.log << " casm ref --set-auto\n";
279  args.log << " - set all reference states using DFT results for configurations with\n";
280  args.log << " extreme compositions.\n";
281  args.log << " - set reference for compositions outside range of this project to 0.0\n";
282  args.log << "\n";
283  args.log << " casm ref --set \n"
284  " '[{\"Zr\":1, \"energy_per_species\":-8.546979385}, \n"
285  " {\"Zr\":1, \"O\":1, \"energy_per_species\":-9.090697345}]'\n"
286  " - set Zr and ZrO, with given energy per species, as reference states\n\n";
287 
288  args.log << " casm ref --scelname SCEL3_3_1_1_0_2_2 --set \n"
289  " '[{\"Zr\":1, \"energy_per_species\":-8.546979385}, \n"
290  " {\"Zr\":1, \"O\":1, \"energy_per_species\":-9.090697345}]'\n"
291  " - set reference states as specified for configurations in supercell SCEL3_3_1_1_0_2_2\n\n";
292 
293  args.log << " casm ref --configname SCEL3_3_1_1_0_2_2/2 --set \n"
294  " '[{\"Zr\":1, \"energy_per_species\":-8.546979385}, \n"
295  " {\"Zr\":1, \"O\":1, \"energy_per_species\":-9.090697345}]'\n"
296  " - set reference states as specified for configuration SCEL3_3_1_1_0_2_2/2\n\n";
297 
298  args.log << " casm ref --scelname SCEL3_3_1_1_0_2_2 --erase \n"
299  " - erase specialized reference states for configurations in supercell SCEL3_3_1_1_0_2_2\n\n";
300 
301  args.log << " casm ref --configname SCEL3_3_1_1_0_2_2/2 --erase \n"
302  " - erase specialized reference states for configuration SCEL3_3_1_1_0_2_2/2\n\n";
303 
304 
305  if(call_help)
306  return ERR_INVALID_ARG;
307 
308  return 0;
309  }
310 
311  po::notify(vm);
312 
313  scelname = ref_opt.supercell_str();
314  configname = ref_opt.config_str();
315  set_str = ref_opt.set_str();
316  }
317  catch(po::error &e) {
318  args.err_log << "ERROR: " << e.what() << std::endl << std::endl;
319  args.err_log << ref_opt.desc() << std::endl;
320  return ERR_INVALID_ARG;
321  }
322  catch(std::exception &e) {
323  args.err_log << "Unhandled Exception reached the top of main: "
324  << e.what() << ", application will now exit" << std::endl;
325  return ERR_UNKNOWN;
326 
327  }
328 
329  if(root.empty()) {
330  args.err_log.error("No casm project found");
331  args.err_log << std::endl;
332  return ERR_NO_PROJ;
333  }
334 
335 
336  // If 'args.primclex', use that, else construct PrimClex in 'uniq_primclex'
337  // Then whichever exists, store reference in 'primclex'
338  std::unique_ptr<PrimClex> uniq_primclex;
339  PrimClex &primclex = make_primclex_if_not(args, uniq_primclex);
340  const ProjectSettings &set = primclex.settings();
341  double lin_alg_tol = primclex.settings().lin_alg_tol();
342 
343  ClexDescription clex_desc;
344  if(!vm.count("clex")) {
345  clex_desc = set.default_clex();
346  }
347  else {
348  auto it = set.cluster_expansions().find(vm["clex"].as<std::string>());
349  if(it == set.cluster_expansions().end()) {
350  args.err_log.error("Invalid --clex value");
351  args.err_log << vm["clex"].as<std::string>() << " not found.";
352  return ERR_INVALID_ARG;
353  }
354  clex_desc = it->second;
355  }
356 
357  std::string calctype = clex_desc.calctype;
358  std::string ref = clex_desc.ref;
359  fs::path chem_ref_path = primclex.dir().chemical_reference(calctype, ref);
360  int result_code = 0;
361 
362  if(vm.count("display")) {
363  if(!primclex.has_chemical_reference()) {
364  args.err_log << "Error using 'casm ref --display': No reference found.\n";
365  args.err_log << " Expected file at: " << chem_ref_path << "\n";
366  args.err_log << "Use 'casm ref --set' or 'casm ref --set-auto' to set a reference\n";
367  return ERR_MISSING_INPUT_FILE;
368  }
369 
370  ChemicalReferencePrinter p(args.log, primclex.chemical_reference());
371  p.print_all();
372 
373  result_code = 0;
374  }
375  else if(vm.count("set-auto")) {
376  try {
377  args.log << " Set reference states automatically.\n\n" << std::endl;
378  ChemicalReference chem_ref = auto_chemical_reference(primclex, lin_alg_tol);
379  ChemicalReferencePrinter p(args.log, chem_ref);
380  p.print_all();
381  write_chemical_reference(chem_ref, chem_ref_path);
382  result_code = 0;
383  }
384  catch(std::exception &e) {
385  args.err_log << "Error setting reference states automatically.\n\n";
386  args.err_log << e.what() << std::endl;
387  return ERR_UNKNOWN;
388  }
389  }
390  else if(vm.count("set")) {
391 
392  using namespace ref_impl;
393 
394  jsonParser json_ref;
395  try {
396  json_ref = jsonParser::parse(set_str);
397  }
398  catch(std::exception &e) {
399  args.err_log << "Error parsing JSON input for 'casm ref --set ' with: \n"
400  << set_str << std::endl;
401  args.err_log << e.what() << std::endl;
402  return ERR_INVALID_ARG;
403  }
404 
405  // --- Set project-wide ref
406 
407  if(!(vm.count("scelname") + vm.count("configname"))) {
408 
409  if(!fs::exists(chem_ref_path)) {
410  // -- Initializing ref
411  result_code = initialize_global(chem_ref_path, primclex, json_ref, lin_alg_tol);
412  }
413  else {
414  // -- Updating project-wide ref
415  result_code = update_global(chem_ref_path, primclex, json_ref, lin_alg_tol);
416  }
417  }
418 
419  // --- Set config specific ref
420 
421  else if(vm.count("configname")) {
422 
423  result_code = update_config(configname, chem_ref_path, primclex, json_ref, lin_alg_tol);
424  }
425 
426  // --- Set supercell specific ref
427 
428  else {
429 
430  result_code = update_supercell(scelname, chem_ref_path, primclex, json_ref, lin_alg_tol);
431 
432  }
433 
434  }
435  else if(vm.count("erase")) {
436 
437  // --- Erase project-wide ref
438 
439  if(!(vm.count("scelname") + vm.count("configname"))) {
440 
441  if(!fs::exists(chem_ref_path)) {
442  args.err_log << "No chemical reference found. \n";
443  return ERR_INVALID_ARG;
444  }
445  else {
446  fs::remove(chem_ref_path);
447  args.log << "Erased chemical reference" << std::endl;
448  }
449  }
450 
451  ChemicalReference chem_ref = primclex.chemical_reference();
452 
453  // --- Erase configuration specific ref
454 
455  if(vm.count("configname")) {
456  if(!chem_ref.erase_config(configname)) {
457  args.err_log << "No " << configname << " specialized reference found. \n";
458  return ERR_INVALID_ARG;
459  }
460  else {
461  args.log << "Erased specialized reference for " << configname << std::endl;
462  write_chemical_reference(chem_ref, chem_ref_path);
463  }
464  }
465 
466  // --- Erase supercell specific ref
467 
468  else {
469  if(!chem_ref.erase_supercell(scelname)) {
470  args.err_log << "No " << scelname << " specialized reference found. \n";
471  return ERR_INVALID_ARG;
472  }
473  else {
474  args.log << "Erased specialized reference for " << scelname << std::endl;
475  write_chemical_reference(chem_ref, chem_ref_path);
476  }
477  }
478 
479  result_code = 0;
480 
481  }
482 
483  if(!result_code) {
484  if(args.primclex) {
485  args.primclex->refresh(false, false, true, false);
486  }
487  }
488 
489  return result_code;
490  }
491 
492 }
Data structure holding basic CASM command info.
int update_global(fs::path chem_ref_path, const PrimClex &primclex, const jsonParser &json_ref, double lin_alg_tol)
Definition: ref.cc:25
Specifies a particular cluster expansion.
#define ERR_UNKNOWN
ChemicalReference auto_chemical_reference(const PrimClex &primclex, double lin_alg_tol)
Automatically set ChemicalReference using calculated Configurations with 'extreme' compositions...
#define ERR_INVALID_ARG
Specification of CASM project directory structure.
const DirectoryStructure & dir() const
Definition: PrimClex.hh:112
void initialize() override
Fill in the options descriptions accordingly.
Definition: ref.cc:137
Structure specifies the lattice and atomic basis of a crystal.
Definition: Structure.hh:29
PrimClex * primclex
Definition: settings.cc:101
const std::string & config_str() const
Returns the name of the supercell for add_configname_suboption(), for when multiple=false.
Definition: Handlers.cc:200
void add_help_suboption()
Add a plain –help suboption.
Definition: Handlers.cc:276
void add_configname_suboption()
Add a –configname suboption.
Definition: Handlers.cc:354
void refresh(bool read_settings=false, bool read_composition=false, bool read_chem_ref=false, bool read_configs=false, bool clear_clex=false)
Reload PrimClex data from settings.
Definition: PrimClex.cc:90
void write_chemical_reference(const ChemicalReference &chem_ref, fs::path filename)
Definition: AppIO.cc:258
int update_supercell(std::string scelname, fs::path chem_ref_path, const PrimClex &primclex, const jsonParser &json_ref, double lin_alg_tol)
Definition: ref.cc:87
Main CASM namespace.
Definition: complete.cpp:8
fs::path prim() const
Return prim.json path.
Represents a supercell of the primitive parent crystal structure.
Definition: Supercell.hh:37
Log & log() const
Definition: Log.hh:255
ProjectSettings & set
Definition: settings.cc:103
BasicStructure< Site > read_prim(fs::path filename)
Definition: AppIO.cc:11
std::vector< std::string > get_struc_molecule_name() const
Returns an Array of each possible Molecule in this Structure.
Definition: Structure.cc:166
pair_type ref
Definition: settings.cc:110
bool has_chemical_reference() const
check if ChemicalReference object initialized
Definition: PrimClex.cc:245
int update_config(std::string configname, fs::path chem_ref_path, const PrimClex &primclex, const jsonParser &json_ref, double lin_alg_tol)
Definition: ref.cc:46
void set_supercell(const std::string &scelname, const Eigen::VectorXd &ref)
Set hyperplane reference specialized for a Supercell.
size_type erase_config(const std::string &configname)
Erase hyperplane reference specialized for a Configuration.
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.
void set_config(const std::string &configname, const Eigen::VectorXd &ref)
Set hyperplane reference specialized for a Configuration.
std::pair< Eigen::VectorXd, std::vector< ChemicalReferenceState > > one_chemical_reference_from_json(const Structure &prim, const jsonParser &json)
Read chemical reference from one of 3 alternative forms.
Definition: clex.cc:180
pair_type calctype
Definition: settings.cc:109
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
PrimClex is the top-level data structure for a CASM project.
Definition: PrimClex.hh:52
const std::string & supercell_str() const
Returns the name of the supercell for add_scelname_suboption()
Definition: Handlers.cc:208
int ref_command(const CommandArgs &args)
Definition: ref.cc:161
ChemicalReference read_chemical_reference(fs::path filename, const Structure &prim, double tol)
Read chemical reference states from JSON file.
Definition: AppIO.cc:212
size_type erase_supercell(const std::string &scelname)
Erase hyperplane reference specialized for a Supercell.
const ChemicalReference & chemical_reference() const
const Access ChemicalReference object
Definition: PrimClex.cc:251
const Configuration & configuration(const std::string &configname) const
access configuration by name (of the form "scellname/[NUMBER]", e.g., ("SCEL1_1_1_1_0_0_0/0") ...
Definition: PrimClex.cc:347
Structure to help print ChemicalReference.
const std::map< std::string, ClexDescription > & cluster_expansions() const
ConfigIO::GenericConfigFormatter< std::string > configname()
Constructs DataFormmaterDictionary containing all Configuration DatumFormatters.
Definition: ConfigIO.cc:340
void add_scelname_suboption()
Add a –scelname suboption.
Definition: Handlers.cc:338
void set_global(const Eigen::VectorXd &ref)
Set global hyperplane reference.
DirectoryStructure & dir
Definition: settings.cc:102
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...
static jsonParser parse(const std::string &str)
Construct a jsonParser from a string containing JSON data.
Definition: jsonParser.hh:312
const Supercell & get_supercell(Index i) const
const Access supercell by index
Definition: PrimClex.cc:311
int initialize_global(fs::path chem_ref_path, const PrimClex &primclex, const jsonParser &json_ref, double lin_alg_tol)
Definition: ref.cc:11
void error(const std::string &what)
Definition: Log.hh:86
ConfigIO::GenericConfigFormatter< std::string > scelname()
Definition: ConfigIO.cc:348
static jsonParser object()
Returns an empty json object.
Definition: jsonParser.hh:329
#define ERR_MISSING_INPUT_FILE
const ClexDescription & default_clex() const
fs::path chemical_reference(std::string calctype, std::string ref) const
Return chemical reference file path.
const std::string & set_str() const
Definition: ref.cc:133
A Configuration represents the values of all degrees of freedom in a Supercell.
const Structure & get_prim() const
const Access to primitive Structure
Definition: PrimClex.cc:260
Log & err_log() const
Definition: Log.hh:263
double lin_alg_tol() const
Get current project linear algebra tolerance.
#define ERR_NO_PROJ