12 namespace Update_impl {
16 using Data = std::tuple<jsonParser, bool, bool>;
44 "Adjusts cost function for mapping optimization (cost=w*lattice_deformation+(1-w)*basis_deformation)")
45 (
"max-vol-change", po::value<double>(&
m_vol_tolerance)->default_value(0.3),
46 "Adjusts range of SCEL volumes searched while mapping imported structure onto ideal crystal (only necessary if the presence of vacancies makes the volume ambiguous). Default is +/- 25% of relaxed_vol/prim_vol. Smaller values yield faster execution, larger values may yield more accurate mapping.")
47 (
"max-va-frac", po::value<double>(&
m_max_va_frac)->default_value(0.5),
48 "Places upper bound on the fraction of sites that are allowed to be vacant after relaxed structure is mapped onto the ideal crystal. Smaller values yield faster execution, larger values may yield more accurate mapping. Has no effect if supercell volume can be inferred from the number of atoms in the structure. Default value allows up to 50% of sites to be vacant.")
49 (
"min-va-frac", po::value<double>(&
m_min_va_frac)->default_value(0.),
50 "Places lower bound on the fraction of sites that are allowed to be vacant after relaxed structure is mapped onto the ideal crystal. Nonzero values may yield faster execution if updating configurations that are known to have a large number of vacancies, at potential sacrifice of mapping accuracy. Has no effect if supercell volume can be inferred from the number of atoms in the structure. Default value allows as few as 0% of sites to be vacant.")
51 (
"force,f",
"Force all configurations to update (otherwise, use timestamps to determine which configurations to update)")
52 (
"strict,s",
"Attempt to import exact configuration.");
67 double lattice_weight;
72 po::store(po::parse_command_line(args.
argc, args.
argv, update_opt.
desc()), vm);
77 if(vm.count(
"help")) {
78 args.
log << std::endl;
79 args.
log << update_opt.
desc() << std::endl;
84 if(vm.count(
"desc")) {
86 args.
log << update_opt.
desc() << std::endl;
87 args.
log <<
"DESCRIPTION" << std::endl;
88 args.
log <<
" Updates all values and files after manual changes or configuration \n";
89 args.
log <<
" calculations.\n";
100 catch(po::error &e) {
102 args.
err_log <<
"ERROR: " << e.what() << std::endl << std::endl;
106 catch(std::exception &e) {
108 args.
err_log <<
"ERROR: " << e.what() << std::endl << std::endl;
121 std::unique_ptr<PrimClex> uniq_primclex;
127 args.
log <<
"Reading calculation data... " << std::endl << std::endl;
128 std::vector<std::string> bad_config_report;
131 Index num_updated(0);
133 std::map<Configuration *, std::map<Configuration *, Update_impl::Data> > update_map;
139 auto end = selection.selected_config_end();
141 for(; it != end; ++it) {
152 fs::path filepath = it->calc_properties_path();
155 if(!fs::exists(filepath)) {
156 if(it->calc_properties().
size() > 0 && !(it->calc_properties().is_null())) {
162 time_t datatime(0), filetime(fs::last_write_time(filepath));
164 it->calc_properties().get_if(datatime,
"data_timestamp");
166 if(!vm.count(
"force") && filetime == datatime) {
171 args.
log << std::endl <<
"***************************" << std::endl << std::endl;
172 args.
log <<
"Working on " << filepath.string() <<
"\n";
174 bool new_config_flag;
175 std::string imported_name;
178 it->read_calc_properties(parsed_props);
180 catch(std::exception &e) {
181 args.
err_log <<
"\nError: Unable to read properties.calc.json" << std::endl;
182 args.
err_log << e.what() << std::endl;
191 std::vector<Index> best_assignment;
196 if(vm.count(
"strict")) {
212 catch(std::exception &e) {
213 args.
err_log <<
"\nError: Unable to map relaxed structure data contained in " << filepath <<
" onto PRIM.\n"
214 <<
" " << e.what() << std::endl;
220 if(imported_name != it->
name() && json.
contains(
"suggested_mapping")) {
221 auto j_it(json[
"suggested_mapping"].cbegin()), j_end(json[
"suggested_mapping"].cend());
222 for(; j_it != j_end; ++j_it) {
223 parsed_props[j_it.name()] = *j_it;
225 update_map[&(*it)][&(*it)] =
Update_impl::Data(parsed_props,
false, new_config_flag);
229 auto j_it(json[
"best_mapping"].cbegin()), j_end(json[
"best_mapping"].cend());
230 for(; j_it != j_end; ++j_it) {
231 parsed_props[j_it.name()] = *j_it;
234 update_map[&imported_config][&(*it)] =
Update_impl::Data(parsed_props, it->
name() == imported_name, new_config_flag);
244 double w = lattice_weight;
245 std::stringstream relax_log;
246 for(
auto it = update_map.begin(); it != update_map.end(); ++it) {
248 std::map<Configuration *, Update_impl::Data> &datamap(it->second);
249 bool self_mapped(
false);
252 std::map<Configuration *, Update_impl::Data>::iterator best_it;
253 double best_cost(1e20);
256 std::vector<std::string> report;
257 for(
auto it2 = datamap.begin(); it2 != datamap.end(); ++it2) {
258 std::stringstream t_ss;
264 const jsonParser &source_data(std::get<Update_impl::relaxjson>(it2->second));
265 if(&source_config == &imported_config) {
266 self_mapped = std::get<Update_impl::self_map>(it2->second);
274 double bd = source_data[
"basis_deformation"].
get<
double>();
275 double ld = source_data[
"lattice_deformation"].
get<
double>();
276 double tcost = w * ld + (1.0 - w) * bd;
278 if(tcost < best_cost) {
283 t_ss <<
"Starting configuration " << source_config.
name() <<
":" << std::endl;
284 t_ss <<
" Result of mapping relaxation onto " << imported_config.
name() << std::endl;
285 t_ss <<
" -- lattice_deformation = " << ld <<
"; basis_deformation = " << bd <<
"; weighted_avg = " << tcost << std::endl;
287 if(&source_config != &imported_config) {
288 jsonParser const &alt_data(std::get<Update_impl::relaxjson>(update_map[&source_config][&source_config]));
289 bd = alt_data[
"basis_deformation"].
get<
double>();
290 ld = alt_data[
"lattice_deformation"].
get<
double>();
291 tcost = w * ld + (1.0 - w) * bd;
292 t_ss <<
" Result of mapping relaxation onto " << source_config.name() << std::endl;
293 t_ss <<
" -- lattice_deformation = " << ld <<
"; basis_deformation = " << bd <<
"; weighted_avg = " << tcost << std::endl;
295 if(source_data.
contains(
"relaxed_energy")) {
296 double energy = source_data[
"relaxed_energy"].
get<
double>();
297 if(energy < lowest_energy)
299 t_ss <<
" -- relaxed_energy = " << source_data[
"relaxed_energy"].
get<
double>() << std::endl;
302 t_ss <<
" -- relaxed_energy = unknown" << std::endl;
303 report.push_back(t_ss.str());
305 Index best_ind(std::distance(datamap.begin(), best_it));
306 if(datamap.size() > 1 || (!self_mapped && datamap.find(&imported_config) == datamap.end())) {
307 relax_log <<
" " << datamap.size() <<
" structure" << (datamap.size() > 1 ?
"s have" :
" has") <<
" mapped onto Configuration " << imported_config.
name()
308 <<
", which " << (std::get<Update_impl::new_config>(datamap.cbegin()->second)
309 ?
"has been automatically added to your project"
310 :
"already existed in your project")
311 << std::endl << std::endl;
313 for(
Index i = 0; i < report.size(); i++) {
315 relax_log <<
" best ==> " << i + 1 <<
") " << report[i] << std::endl;
318 relax_log <<
" " << i + 1 <<
") " << report[i] << std::endl;
323 fs::path filepath((best_it->first)->calc_properties_path());
324 jsonParser &parsed_props(std::get<Update_impl::relaxjson>(best_it->second));
328 relax_log <<
" Because no calculation data exists for configuration " << imported_config.
name() <<
",\n"
329 <<
" it will acquire the data from " << filepath <<
"\n";
335 import_target.remove_filename();
336 if(!fs::exists(import_target))
337 fs::create_directories(import_target);
350 relax_log <<
" There is already data associated with " << imported_config.
name() <<
" -- it will not be overwritten.\n\n";
352 bool data_mismatch =
false;
354 auto prop_it = extant_props.
cbegin(), prop_end = extant_props.
cend();
355 for(; prop_it != prop_end; ++prop_it) {
356 if(!parsed_props.contains(prop_it.name())) {
357 data_mismatch =
true;
362 if(!prop_it->is_number() || (prop_it.name()).
find(
"energy") == std::string::npos)
365 if(!
almost_equal(prop_it->get<
double>(), parsed_props[prop_it.name()].get<
double>(), 1e-4)) {
366 if(parsed_props[prop_it.name()].get<
double>() < prop_it->get<
double>()) {
367 relax_log <<
"\n WARNING: Mapped configuration " << imported_config.
name() <<
" has \n"
368 <<
" " << prop_it.name() <<
"=" << prop_it->get<
double>() <<
"\n"
369 <<
" Which is higher than the relaxed value for mechanically unstable configuration " << (best_it->first)->name() <<
" which is\n"
370 <<
" " << prop_it.name() <<
"=" << parsed_props[prop_it.name()].get<
double>() <<
"\n"
371 <<
" This suggests that " << imported_config.
name() <<
" may be a metastable minimum. Please investigate further.\n";
374 data_mismatch =
true;
378 relax_log <<
" WARNING: There are calculated properties from \n"
379 <<
" " << filepath <<
"\n"
380 <<
" that do not match existing calculations for configuration " << imported_config.
name() <<
" (they differ by more than 1E-04)\n"
381 <<
" even though " << (best_it->first)->name() <<
" was found to relax to " << imported_config.
name() <<
"\n";
383 relax_log <<
"\n ----------------------------------------------\n" << std::endl;
384 if(self_mapped && datamap.find(&imported_config) != datamap.end())
385 imported_config.
set_calc_properties(std::get<Update_impl::relaxjson>(datamap[&imported_config]));
387 else if(self_mapped) {
396 args.
log << std::endl <<
"***************************" << std::endl << std::endl;
397 args.
log <<
" DONE: ";
399 args.
log <<
"No new data were detected." << std::endl << std::endl;
401 args.
log <<
"Analyzed new data for " << num_updated <<
" configurations." << std::endl << std::endl;
403 if(relax_log.str().size() > 0) {
404 args.
log <<
"WARNING: Abnormal relaxations were detected:\n" << std::endl
405 <<
" *** Final Relaxation Report ***" << std::endl
407 << std::endl << std::endl;
408 args.
log <<
"\nIt is recommended that you review these configurations more carefully.\n" << std::endl;
411 args.
log <<
"Writing to SCEL database..." << std::endl << std::endl;
414 args.
log <<
"Writing to configuration database..." << std::endl << std::endl;
Data structure holding basic CASM command info.
size_type size() const
Returns array size if *this is a JSON array, object size if *this is a JSON object, 1 otherwise.
int update_command(const CommandArgs &args)
void write_config_list(std::set< std::string > scel_to_delete={})
void from_json(ClexDescription &desc, const jsonParser &json)
fs::path calc_properties_path() const
void add_help_suboption()
Add a plain –help suboption.
iterator selected_config_begin()
void push_back_source(const jsonParser &source)
bool import_structure(const fs::path &pos_path, std::string &imported_name, jsonParser &relaxation_properties, std::vector< Index > &best_assignment, Eigen::Matrix3d &cart_op) const
imports structure specified by 'pos_path' into primclex() by finding optimal mapping unlike import_st...
void add_configlist_suboption(const fs::path &_default="MASTER")
Add –config suboption (defaults to MASTER)
const_iterator cend() const
Returns const_iterator to end of JSON object or JSON array.
const fs::path & selection_path() const
Returns the string corresponding to add_config_suboption()
T get(Args...args) const
Get data from json, using one of several alternatives.
const std::vector< std::string > & properties() const
Get current properties.
const Properties & calc_properties() const
bool is_null() const
Check if null type.
const po::options_description & desc()
Get the program options, filled with the initialized values.
fs::path get_pos_path() const
Path to various files.
double lattice_weight() const
void set_min_va_frac(double _min_va)
EigenIndex Index
For long integer indexing:
po::options_description m_desc
Boost program options. All the derived classes have them, but will fill them up themselves.
ProjectSettings & settings()
Iterator find(Iterator begin, Iterator end, const T &value, BinaryCompare q)
Equivalent to std::find(begin, end, value), but with custom comparison.
PrimClex is the top-level data structure for a CASM project.
std::tuple< jsonParser, bool, bool > Data
T max(const T &A, const T &B)
double max_va_frac() const
SimpleJSonSiteStructure< true > simple_json(const BasicStructure< Site > &struc, const std::string &prefix)
std::string name() const
SCELV_A_B_C_D_E_F/i.
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") ...
void print_supercells(std::set< std::string > scel_to_delete={}) const
void set_calc_properties(const jsonParser &json)
Read calculation results into the configuration.
void set_max_va_frac(double _max_va)
jsonParser & put_obj()
Puts new empty JSON object.
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...
void initialize() override
Fill in the options descriptions accordingly.
double vol_tolerance() const
bool contains(const std::string &name) const
Return true if JSON object contains 'name'.
void error(const std::string &what)
double min_va_frac() const
const_iterator cbegin() const
Returns const_iterator to beginning of JSON object or JSON array.
bool almost_equal(const GenericCluster< CoordType > &LHS, const GenericCluster< CoordType > &RHS, double tol)
A Configuration represents the values of all degrees of freedom in a Supercell.
bool import_structure_occupation(const fs::path &pos_path, std::string &imported_name, jsonParser &relaxation_properties, std::vector< Index > &best_assignment, Eigen::Matrix3d &cart_op) const
imports structure specified by 'pos_path' into primclex() by finding optimal mapping and then setting...
#define ERR_INVALID_INPUT_FILE
const std::string & name() const