CASM  1.1.0
A Clusters Approach to Statistical Mechanics
init.cc
Go to the documentation of this file.
1 #include <boost/filesystem.hpp>
2 #include <boost/filesystem/fstream.hpp>
3 #include <cstring>
4 
10 #include "casm/casm_io/Log.hh"
13 #include "casm/clex/PrimClex.hh"
26 
27 namespace CASM {
28 
29 const std::string subproject_opt = "sub";
30 
31 const std::string write_prim_opt = "write-prim";
32 
33 const std::string relaxed_opt = "relaxed";
34 
35 const std::string molecule_opt = "as-molecules";
36 
37 const std::string include_va_opt = "include-va";
38 
39 // returns {error message, new file extension, new structure}
40 std::tuple<std::string, std::string, BasicStructure> standardize_prim(
41  BasicStructure const &prim, bool force) {
44  std::string err;
45  if (true_prim.basis().size() < prim.basis().size()) {
46  // err
47  err +=
48  " The structure in the provided file is not primitive. Some "
49  "CASM\n"
50  " features cannot be used with a non-primitive starting "
51  "structure.\n\n";
52 
53  if (!force) {
54  // current is_primitive
55  Lattice lat_niggli = xtal::canonical::equivalent(true_prim.lattice());
56  true_prim.set_lattice(lat_niggli, CART);
57  return {err, ".primitive.json", true_prim};
58  }
59  }
60 
62  Lattice niggli_lat = xtal::canonical::equivalent(prim.lattice());
63 
64  bool is_standard_niggli = almost_equal(niggli_lat.lat_column_mat(),
65  prim.lattice().lat_column_mat());
66 
67  if (!is_standard_niggli) {
68  err +=
69  " The structure in the provided file is not the Niggli cell in "
70  "the CASM\n"
71  " standard orientation.\n\n";
72 
73  if (!force) {
74  xtal::BasicStructure tmp(prim);
75  tmp.set_lattice(niggli_lat, CART);
76  return {err, ".niggli.json", tmp};
77  }
78  }
79 
80  // Check if the lattice is right handed, and if not print
81  // PRIM.right_handed.json
82  if (!prim.lattice().is_right_handed()) {
83  err +=
84  " The lattice vectors of the provided structure do not form a "
85  "right-handed\n"
86  " coordinate system. Some electronic-structure codes will not "
87  "accept this\n"
88  " input.\n\n";
89 
90  if (!force) {
91  xtal::BasicStructure tmp(prim);
93  tmp.within();
94  return {err, ".right_handed.json", tmp};
95  }
96  }
97  return {err, "", prim};
98 }
99 
100 namespace Completer {
102 
105  add_prim_path_suboption("prim.json");
107  add_configlist_suboption("NONE");
111  m_desc.add_options()(
112  subproject_opt.c_str(),
113  "Initialize a project in sub-directory of an existing project. After "
114  "initialization, commands executed below the sub-directory will act on "
115  "the sub-directory project; commmands executed above the sub-directory "
116  "act on the original project.")(
117  write_prim_opt.c_str(),
118  "Create prim.json file for specified configuration(s). Each prim.json is "
119  "written to the training_data directory of the corresponding "
120  "configuration.")(relaxed_opt.c_str(),
121  "Utilize relaxed coordinates for writing "
122  "configuration-specific prim.json files.")(
123  molecule_opt.c_str(),
124  "Keep multi-atom species as molecules. By default, multi-atom species "
125  "are split into constituent atoms.")(
126  include_va_opt.c_str(),
127  "Print sites that can only be vacancies; otherwise these sites are "
128  "excluded.")(
129  "force,f",
130  "Force using a non-reduced, non-primitive, or left-handed PRIM.");
131  return;
132 }
133 } // namespace Completer
134 
135 // ///////////////////////////////////////
136 // 'init' function for casm
137 // (add an 'if-else' statement in casm.cpp to call this)
138 
139 int init_command(const CommandArgs &args) {
140  std::string name;
141  po::variables_map vm;
142 
144  Completer::InitOption init_opt;
145 
146  try {
147  po::store(po::parse_command_line(args.argc(), args.argv(), init_opt.desc()),
148  vm); // can throw
149 
152  if (vm.count("help")) {
153  log() << "\n";
154  log() << init_opt.desc() << std::endl;
155 
156  return 0;
157  }
158 
159  if (vm.count("desc")) {
160  log() << "\n";
161  log() << init_opt.desc() << std::endl;
162 
163  log()
164  << "DESCRIPTION \n"
165  << " Initialize a new CASM project in the current directory.\n"
166  << " - Expects a prim.json file in the current directory \n"
167  << " - If not found, looks for a PRIM file in the current \n"
168  << " directory and creates prim.json. \n\n";
169 
170  return 0;
171  }
172 
173  po::notify(vm); // throws on error, so do after help in case
174  // there are any problems
175  } catch (po::error &e) {
176  err_log() << "ERROR: " << e.what() << std::endl << std::endl;
177  err_log() << init_opt.desc() << std::endl;
178  return ERR_INVALID_ARG;
179  } catch (std::exception &e) {
180  err_log() << "Unhandled Exception reached the top of main: " << e.what()
181  << ", application will now exit" << std::endl;
182  return ERR_UNKNOWN;
183  }
184 
185  fs::path root = fs::current_path();
186  if (!init_opt.file_path().empty()) {
187  root = init_opt.file_path();
188  } else if (!args.root.empty()) {
189  root = args.root;
190  }
191 
192  // Going to do conversion:
193  if (vm["config"].defaulted() && init_opt.config_strs().empty()) {
194  DirectoryStructure dir(root);
195  BasicStructure prim;
196  // Read PRIM or prim.json:
197  try {
198  prim = read_prim(init_opt.prim_path(), TOL);
199  } catch (std::exception &e) {
200  err_log() << e.what() << std::endl;
201  return ERR_INVALID_INPUT_FILE;
202  }
203 
204  // Add the new DoFs before doing anything else
205  std::map<DoFKey, xtal::DoFSet> new_global_dofs = prim.global_dofs();
206  std::map<DoFKey, xtal::SiteDoFSet> new_site_dofs;
207  for (std::string const &doftype : init_opt.dof_strs()) {
208  AnisoValTraits ttraits(doftype);
209  if (ttraits.global() && !new_global_dofs.count(doftype))
210  new_global_dofs.emplace(doftype, ttraits);
211  else
212  new_site_dofs.emplace(doftype, ttraits);
213  }
214  prim.set_global_dofs(new_global_dofs);
215 
216  for (xtal::Site &site : prim.set_basis()) {
217  std::map<DoFKey, xtal::SiteDoFSet> site_dofs = site.dofs();
218  site_dofs.insert(new_site_dofs.begin(), new_site_dofs.end());
219  site.set_dofs(std::move(site_dofs));
220  }
221 
222  // Check if prim is standardized
223  std::string err_msg;
224  std::string extension;
225  std::tie(err_msg, extension, prim) =
226  standardize_prim(prim, vm.count("force"));
227 
228  // Check error message to see if PRIM did not meet standards; report if so
229  if (!err_msg.empty()) {
230  if (vm.count("force")) {
231  err_log() << "WARNING: " << init_opt.prim_path()
232  << " failed the following check(s): \n"
233  << err_msg
234  << "Continuing due to usage of '--force' modifier.\n\n";
235  } else {
236  std::string new_path = init_opt.prim_path().string();
237  std::string tpath = new_path.substr(0, new_path.find(".json"));
238  new_path = tpath.substr(0, new_path.find(".JSON"));
239  new_path += extension;
240  err_log() << "Validation ERROR for " << init_opt.prim_path() << ":\n"
241  << err_msg
242  << "Standardizing structure and writing to JSON file: "
243  << new_path << "\n";
244  write_prim(prim, new_path, init_opt.coordtype_enum(),
245  vm.count(include_va_opt));
246  err_log() << "To initialize your project anyway, use the --force "
247  "option."
248  << std::endl;
249  return ERR_INVALID_INPUT_FILE;
250  }
251  }
252  if (vm.count(write_prim_opt)) {
253  jsonParser json_prim;
254  write_prim(prim, json_prim, init_opt.coordtype_enum(),
255  vm.count(include_va_opt));
256  log() << json_prim << std::endl;
257  } else {
258  log() << "\n***************************\n" << std::endl;
259  // Actually going to initialize:
260  root = fs::current_path();
261  if (!init_opt.file_path().empty()) {
262  root = init_opt.file_path();
263  }
264  fs::path existing = find_casmroot(root);
265  if (vm.count(subproject_opt)) {
266  if (existing == root) {
267  log() << "Directory '" << root
268  << "' is already the head directory of a casm project."
269  << std::endl;
270  return ERR_OTHER_PROJ;
271  }
272  if (existing.empty()) {
273  log() << "Cannot create sub-directory project at '" << root
274  << "' because no existing project was found at a higher level."
275  << std::endl
276  << "To initialize a top-level project, try again without the --"
277  << subproject_opt << "flag." << std::endl;
278  return ERR_OTHER_PROJ;
279  }
280  } else if (!existing.empty()) {
281  log() << "Already in a casm project. To create a project at " << root
282  << ", try again using the --" << subproject_opt << " flag."
283  << std::endl;
284  return ERR_OTHER_PROJ;
285  } // End new control block
286 
287  try {
288  // std::string orig_prim_title = prim.title;
289  if (prim.title().empty() || !is_valid_project_name(prim.title())) {
290  log() << "Please enter a short title for this project.\n";
291  log() << " Use something suitable as a prefix for files specific to "
292  "this project, such as 'ZrO' or 'TiAl'.\n\n";
293 
294  std::string ttitle;
295  log() << "Title: ";
296  std::cin >> ttitle;
297  log() << "\n\n";
298  prim.set_title(ttitle);
299  }
300  log() << "Initializing CASM project '" << prim.title() << "'"
301  << std::endl;
302  auto project_settings =
303  make_default_project_settings(prim, prim.title(), root);
304  build_project(project_settings, Structure{prim});
305  } catch (std::runtime_error &e) {
306  err_log() << "ERROR: Could not build CASM project.\n";
307  err_log() << e.what() << std::endl;
308  return ERR_INVALID_INPUT_FILE;
309  }
310 
311  log() << " DONE" << std::endl;
312  log() << std::endl;
313  }
314  } else if (vm.count(write_prim_opt)) {
315  log() << "\n***************************\n" << std::endl;
316 
317  // Start from config in existing project:
318  // If 'args.primclex', use that, else construct PrimClex in 'uniq_primclex'
319  // Then whichever exists, store reference in 'primclex'
320 
321  std::unique_ptr<PrimClex> uniq_primclex;
322  PrimClex &primclex = make_primclex_if_not(args, uniq_primclex);
323 
325  init_opt.selection_path());
326  for (std::string const &config : init_opt.config_strs()) {
327  config_select.data()[config] = true;
328  }
329  for (const auto &config : config_select.selected()) {
330  SimpleStructure::SpeciesMode species_mode =
331  SimpleStructure::SpeciesMode::ATOM;
332  if (vm.count(molecule_opt))
333  species_mode = SimpleStructure::SpeciesMode::MOL;
334  SimpleStructure sstruc =
335  make_simple_structure(config, {}, vm.count(relaxed_opt));
336  BasicStructure new_prim =
337  xtal::make_basic_structure(sstruc, init_opt.dof_strs(), species_mode);
338  fs::path config_dir = primclex.dir().configuration_dir(config.name());
339  try {
340  fs::create_directories(config_dir);
341  } catch (const fs::filesystem_error &ex) {
342  err_log() << "Error making directory " << config_dir << std::endl;
343  err_log() << ex.what() << std::endl;
344  }
345 
346  std::string prim_title = config.name();
347  auto it = prim_title.begin();
348  for (; it != prim_title.end(); ++it) {
349  if ((*it) == '/') {
350  (*it) = 'c';
351  break;
352  }
353  }
354 
355  prim_title.insert(it, '_');
356 
357  new_prim.set_title(prim_title);
358 
359  write_prim(new_prim, config_dir / "prim.json", init_opt.coordtype_enum(),
360  vm.count(include_va_opt));
361 
362  log() << "Wrote file " << (config_dir / "prim.json") << std::endl;
363  }
364  }
365 
366  return 0;
367 };
368 
369 } // namespace CASM
#define ERR_UNKNOWN
Definition: errors.hh:10
#define ERR_INVALID_ARG
Definition: errors.hh:7
#define ERR_INVALID_INPUT_FILE
Definition: errors.hh:16
#define ERR_OTHER_PROJ
Definition: errors.hh:29
Specifies traits of (possibly) anisotropic crystal properties.
bool global() const
Returns true if type is global.
int argc() const
Definition: CLIParse.hh:20
char ** argv() const
Definition: CLIParse.hh:22
COORD_TYPE coordtype_enum() const
Return the coordinate type recasted as the CASM defined enum.
Definition: Handlers.cc:398
const std::vector< std::string > & config_strs() const
Definition: Handlers.cc:382
void initialize() override
Fill in the options descriptions accordingly.
Definition: init.cc:103
const fs::path & selection_path() const
Returns the string corresponding to add_config_suboption()
Definition: Handlers.cc:338
const fs::path & prim_path() const
Returns the string corsresponding to add_prim_path_suboption()
Definition: Handlers.cc:348
const std::vector< std::string > & dof_strs() const
Returns the names of the DoF type names for add_dofs_suboption()
Definition: Handlers.cc:403
const fs::path & file_path() const
Returns the string corsresponding to add_file_path_suboption()
Definition: Handlers.cc:346
void add_prim_path_suboption(const fs::path &_default="")
Add –prim suboption.
Definition: Handlers.cc:500
void add_confignames_suboption()
Add a –confignames suboption.
Definition: Handlers.cc:691
const po::options_description & desc()
Get the program options, filled with the initialized values.
Definition: Handlers.cc:321
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_configlist_suboption(const fs::path &_default="MASTER")
Add –config suboption (defaults to MASTER)
Definition: Handlers.cc:431
void add_coordtype_suboption()
Add a –coord suboption to specify FRAC or CART.
Definition: Handlers.cc:725
void add_dofs_suboption()
Add a –dofs suboption to specify DoF Types.
Definition: Handlers.cc:737
void add_file_path_suboption(const fs::path &_default="")
Add –path suboption (defaults to MASTER)
Definition: Handlers.cc:490
boost::iterator_range< iterator > selected()
Definition: Selection.cc:237
map_type & data()
Definition: Selection.cc:250
Specification of CASM project directory structure.
fs::path configuration_dir(std::string configname) const
Return configuration directory path.
PrimClex is the top-level data structure for a CASM project.
Definition: PrimClex.hh:55
Structure specifies the lattice and atomic basis of a crystal.
Definition: Structure.hh:30
BasicStructure specifies the lattice and atomic basis of a crystal.
void set_lattice(const Lattice &lattice, COORD_TYPE mode)
std::map< DoFKey, DoFSet > const & global_dofs() const
std::vector< Site > & set_basis()
const std::string & title() const
void set_title(std::string const &_title)
Set the title of the structure.
void within()
Translate all basis sites so that they are inside the unit cell.
const Lattice & lattice() const
void set_global_dofs(std::map< DoFKey, DoFSet > const &new_dof_map)
Manually set the global DoFs.
const std::vector< Site > & basis() const
bool is_right_handed() const
Check if the lattice is right handed.
Definition: Lattice.cc:751
const Eigen::Matrix3d & lat_column_mat() const
3x3 matrix with lattice vectors as its columne
Definition: Lattice.hh:110
Lattice & make_right_handed()
Flip c vector if it's on the wrong side of a-b plane – return (*this)
Definition: Lattice.cc:466
Representation of a crystal of molecular and/or atomic occupants, and any additional properties....
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...
DB::Database< T > & db() const
Definition: PrimClex.cc:302
const DirectoryStructure & dir() const
Access DirectoryStructure object. Throw if not set.
Definition: PrimClex.cc:230
bool is_valid_project_name(std::string project_name)
ConfigIO::GenericConfigFormatter< jsonParser > config()
Definition: ConfigIO.cc:777
SpeciesMode
enum to refer to a particular representation of the occupants (atomic or molecular)
Lattice equivalent(Lattice const &in_lat, SymOpVector const &point_grp, double compare_tol)
BasicStructure make_basic_structure(SimpleStructure const &_sstruc, std::vector< DoFKey > const &_all_dofs, SimpleStructureTools::SpeciesMode mode, std::vector< std::vector< Molecule >> _allowed_occupants={})
Construct BasicStructure from SimpleStructure.
BasicStructure make_primitive(const BasicStructure &non_primitive_struc, double tol=TOL)
Returns the smallest possible tiling unit of the given structure.
Main CASM namespace.
Definition: APICommand.hh:8
bool almost_equal(ClusterInvariants const &A, ClusterInvariants const &B, double tol)
Check if ClusterInvariants are equal.
const std::string relaxed_opt
Definition: init.cc:33
std::tuple< std::string, std::string, BasicStructure > standardize_prim(BasicStructure const &prim, bool force)
Definition: init.cc:40
xtal::SimpleStructure make_simple_structure(Supercell const &_scel, ConfigDoF const &_dof, std::vector< DoFKey > const &_which_dofs={})
Construct from ConfigDoF _dof belonging to provided Supercell _scel.
Log & log()
Definition: Log.hh:424
const std::string molecule_opt
Definition: init.cc:35
void write_prim(const xtal::BasicStructure &prim, fs::path filename, COORD_TYPE mode, bool include_va=false)
Write prim.json to file.
const std::string include_va_opt
Definition: init.cc:37
void build_project(ProjectSettings const &project_settings, Structure const &prim)
const std::string subproject_opt
Definition: init.cc:29
const double TOL
Definition: definitions.hh:30
xtal::BasicStructure read_prim(fs::path filename, double xtal_tol, ParsingDictionary< AnisoValTraits > const *_aniso_val_dict=nullptr)
const std::string write_prim_opt
Definition: init.cc:31
GenericDatumFormatter< std::string, DataObject > name()
fs::path find_casmroot(const fs::path &cwd)
ProjectSettings make_default_project_settings(xtal::BasicStructure const &prim, std::string project_name)
const COORD_TYPE CART
Definition: enum.hh:9
int init_command(const CommandArgs &args)
Definition: init.cc:139
Log & err_log()
Definition: Log.hh:426
PrimClex * primclex
Definition: settings.cc:135
DirectoryStructure const & dir
Definition: settings.cc:136
Data structure holding basic CASM command info.