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