CASM
AClustersApproachtoStatisticalMechanics
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules
ConfigMapping.cc
Go to the documentation of this file.
1 #include "casm/clex/PrimClex.hh"
8 
9 namespace CASM {
10  namespace ConfigMapping {
11  double strain_cost(const Lattice &relaxed_lat, const ConfigDoF &_dof, const Index Nsites) {
12  return LatticeMap::calc_strain_cost(_dof.deformation(), relaxed_lat.vol() / double(max(Nsites, Index(1))));
13  }
14 
15  //*******************************************************************************************
16 
17  double basis_cost(const ConfigDoF &_dof, Index Nsites) {
18  // mean square displacement distance in deformed coordinate system
19  return (_dof.deformation() * _dof.displacement() * _dof.displacement().transpose() * _dof.deformation().transpose()).trace() / double(max(Nsites, Index(1)));
20  }
21 
22  //*******************************************************************************************
24  const Lattice &relaxed_lat,
25  const SymGroup &sym_group,
26  Eigen::Matrix3d &deformation,
27  Eigen::Matrix3d &trans_mat,
28  const std::vector<Lattice> &from_range,
29  double _tol) {
30  Lattice best_lat;
31 
32  double best_cost = 10e10;
33 
34  //std::cout << "min_vol is " << min_vol << "max_vol is " << max_vol << "\n";
35  for(auto it = from_range.cbegin(); it != from_range.cend(); ++it) {
36  //Supercell matches size, now check to see see if lattices are related to each other
37  LatticeMap strainmap(*it, relaxed_lat, 1, _tol, 1);
38  if(strainmap.best_strain_mapping().strain_cost() < best_cost) {
39  trans_mat = strainmap.matrixN();
40  deformation = strainmap.matrixF();
41  best_cost = strainmap.strain_cost();
42  best_lat = *it;
43  }
44  }
45  //std::cout << "Best strain mapping is " << best_cost << " with F = \n" << deformation << "\n";
46 
47  return best_lat;
48  }
49 
50  //*******************************************************************************************
52  const Lattice &relaxed_lat,
53  const SymGroup &sym_group,
54  Eigen::Matrix3d &deformation,
55  Eigen::Matrix3d &trans_mat,
56  Index min_vol,
57  Index max_vol,
58  double _tol) {
59  Lattice best_lat;
60  if(!valid_index(max_vol))
61  max_vol = ceil(std::abs(relaxed_lat.vol()) / std::abs(prim_lat.vol()));
62 
63  double best_cost = 10e10;
64  //We only bother checking pre-existing supercells of min_vol <= volume <=max_vol;
65  SupercellEnumerator<Lattice> enumerator(prim_lat, sym_group, ScelEnumProps(min_vol, max_vol + 1));
66 
67  //std::cout << "min_vol is " << min_vol << "max_vol is " << max_vol << "\n";
68  for(auto it = enumerator.begin(); it != enumerator.end(); ++it) {
69  //std::cout << "Enumeration step " << l++ << " best cost is " << best_cost << "\n";
70  Lattice tlat = canonical_equivalent_lattice(*it, sym_group, _tol);
71 
72  //Supercell matches size, now check to see see if lattices are related to each other
73  LatticeMap strainmap(tlat, relaxed_lat, 1, _tol, 1);
74  if(strainmap.best_strain_mapping().strain_cost() < best_cost) {
75  trans_mat = strainmap.matrixN();
76  deformation = strainmap.matrixF();
77  best_cost = strainmap.strain_cost();
78  best_lat = tlat;
79  }
80  }
81  //std::cout << "Best strain mapping is " << best_cost << " with F = \n" << deformation << "\n";
82 
83  return best_lat;
84  }
85 
86 
87  }
88 
89  //*******************************************************************************************
90 
92  double _lattice_weight,
93  double _max_volume_change/*=0.5*/,
94  int options/*=robust*/,
95  double _tol/*=TOL*/) :
96  m_pclex(&_pclex),
97  m_lattice_weight(_lattice_weight),
98  m_max_volume_change(_max_volume_change),
99  m_min_va_frac(0.),
100  m_max_va_frac(1.),
101  m_robust_flag(options & robust),
102  m_strict_flag(options & strict),
103  m_rotate_flag(options & rotate),
104  m_tol(max(1e-9, _tol)) {
105  //squeeze lattice_weight into (0,1] if necessary
106  m_lattice_weight = max(min(_lattice_weight, 1.0), 1e-9);
107  ParamComposition param_comp(_pclex.get_prim());
108  m_fixed_components = param_comp.fixed_components();
109  m_max_volume_change = max(m_tol, _max_volume_change);
110  }
111 
112  //*******************************************************************************************
113 
115  std::string &imported_name,
116  jsonParser &relaxation_properties,
117  std::vector<Index> &best_assignment,
118  Eigen::Matrix3d &cart_op) const {
119 
120  try {
121  BasicStructure<Site> tstruc(pos_path);
122  return import_structure_occupation(tstruc,
123  imported_name,
124  relaxation_properties,
125  best_assignment,
126  cart_op);
127  }
128  catch(const std::exception &ex) {
129  throw std::runtime_error(std::string("Could not successfully import structure ") + pos_path.string() + ":\n" + ex.what());
130  }
131 
132 
133  }
134 
135  //*******************************************************************************************
136 
138  std::string &imported_name,
139  jsonParser &relaxation_properties,
140  std::vector<Index> &best_assignment,
141  Eigen::Matrix3d &cart_op,
142  bool update_struc) const {
143  return import_structure_occupation(_struc,
144  nullptr,
145  imported_name,
146  relaxation_properties,
147  best_assignment,
148  cart_op,
149  update_struc);
150  }
151 
152  //*******************************************************************************************
153 
155  const Configuration *hint_ptr,
156  std::string &imported_name,
157  jsonParser &relaxation_properties,
158  std::vector<Index> &best_assignment,
159  Eigen::Matrix3d &cart_op,
160  bool update_struc) const {
161 
162  //Indices for Configuration index and permutation operation index
163  ConfigDoF tconfigdof, suggested_configdof;
164  Lattice mapped_lat;
165  bool is_new_config(true);
166  double bc(1e20), sc(1e20), hint_cost = 1e20;
167 
168  relaxation_properties.put_obj();
169  //std::vector<Index> best_assignment;
170 
171  if(hint_ptr != nullptr) {
173  _struc,
174  suggested_configdof,
175  best_assignment,
176  m_robust_flag, // translate_flag -- not sure what to use for this
177  m_tol)) {
178  mapped_lat = (hint_ptr->get_supercell()).get_real_super_lattice();
179  bc = ConfigMapping::basis_cost(suggested_configdof, _struc.basis.size());
180  sc = ConfigMapping::strain_cost(_struc.lattice(), suggested_configdof, _struc.basis.size());
181  relaxation_properties["suggested_mapping"]["basis_deformation"] = bc;
182  relaxation_properties["suggested_mapping"]["lattice_deformation"] = sc;
183  relaxation_properties["suggested_mapping"]["volume_relaxation"] = suggested_configdof.deformation().determinant();
184  hint_cost = m_lattice_weight * sc + (1.0 - m_lattice_weight) * bc - m_tol;
185  }
186  else {
187  //relaxation_properties["suggested_mapping"] = "unknown";
188  }
189  }
190  if(struc_to_configdof(_struc,
191  tconfigdof,
192  mapped_lat,
193  best_assignment,
194  cart_op,
195  hint_cost)) {
196 
197  bc = ConfigMapping::basis_cost(tconfigdof, _struc.basis.size());
198  sc = ConfigMapping::strain_cost(_struc.lattice(), tconfigdof, _struc.basis.size());
199  // robust_cost = m_lattice_weight * sc + (1.0 - m_lattice_weight) * bc - m_tol;
200  relaxation_properties["best_mapping"]["basis_deformation"] = bc;
201  relaxation_properties["best_mapping"]["lattice_deformation"] = sc;
202  relaxation_properties["best_mapping"]["volume_relaxation"] = tconfigdof.deformation().determinant();
203 
204  }
205  else {
206  if(hint_cost > 1e10)
207  throw std::runtime_error("Structure is incompatible with PRIM.");
208 
209  swap(tconfigdof, suggested_configdof);
210  relaxation_properties["best_mapping"] = relaxation_properties["suggested_mapping"];
211  }
212 
213 
214  ConfigDoF relaxed_occ;
215 
216  relaxed_occ.set_occupation(tconfigdof.occupation());
218 
219  if(hint_ptr != nullptr) {
220  Supercell &scel(hint_ptr->get_supercell());
221  if(mapped_lat.is_equivalent(scel.get_real_super_lattice(), m_tol)) {
222  if(m_strict_flag && relaxed_occ.occupation() == (hint_ptr->configdof()).occupation()) {
223  // config is unchanged
224  imported_name = hint_ptr->name();
225  is_new_config = false;
226  it_canon = hint_ptr->get_supercell().permute_begin();
227  }
228  else {
229 
230  Supercell::permute_const_iterator relaxed_it_canon = Configuration(scel, jsonParser(), relaxed_occ).to_canonical();
231  Supercell::permute_const_iterator ideal_rev_it_canon = hint_ptr->from_canonical();
232  it_canon = ideal_rev_it_canon * relaxed_it_canon;
233 
234  if(relaxed_occ.occupation() == copy_apply(it_canon.inverse(), *hint_ptr).occupation()) {
235  // config is unchanged
236  imported_name = hint_ptr->name();
237  is_new_config = false;
238  }
239  }
240  }
241  }
242 
243  if(is_new_config) {
244  Index import_scel_index = primclex().add_supercell(mapped_lat), import_config_index;
245 
246  Configuration import_config(primclex().get_supercell(import_scel_index), jsonParser(), relaxed_occ);
247 
248  if(m_strict_flag) {
249  it_canon = primclex().get_supercell(import_scel_index).permute_begin();
250  is_new_config = primclex().get_supercell(import_scel_index).add_canon_config(import_config, import_config_index);
251  imported_name = primclex().get_supercell(import_scel_index).get_config(import_config_index).name();
252  }
253  else {
254  is_new_config = primclex().get_supercell(import_scel_index).add_config(import_config, import_config_index, it_canon);
255  imported_name = primclex().get_supercell(import_scel_index).get_config(import_config_index).name();
256  }
257  }
258  else {
259 
260  }
261  // transform deformation tensor to match canonical form and apply operation to cart_op
262  ConfigDoF trans_configdof = copy_apply(it_canon, tconfigdof);
263  relaxation_properties["best_mapping"]["relaxation_deformation"] = trans_configdof.deformation();
264  relaxation_properties["best_mapping"]["relaxation_displacement"] = trans_configdof.displacement().transpose();
265 
266  cart_op = it_canon.sym_op().matrix() * cart_op;
267 
268  // compose permutations
269  std::vector<Index>tperm = it_canon.combined_permute().permute(best_assignment);
270 
271  //copy non-vacancy part of permutation into best_assignment
272  best_assignment.resize(_struc.basis.size());
273  Index num_atoms = _struc.basis.size();
274  std::copy_if(tperm.cbegin(), tperm.cend(),
275  best_assignment.begin(),
276  [num_atoms](Index i) {
277  return i < num_atoms;
278  });
279 
280  if(update_struc) {
281  _struc.set_lattice(Lattice(cart_op.transpose()*tconfigdof.deformation()*mapped_lat.lat_column_mat()), CART);
282  _struc.set_lattice(Lattice(tconfigdof.deformation()*mapped_lat.lat_column_mat()), FRAC);
283  }
284  return is_new_config;
285  }
286 
287  //*******************************************************************************************
288 
290  std::string &imported_name,
291  jsonParser &relaxation_properties,
292  std::vector<Index> &best_assignment,
293  Eigen::Matrix3d &cart_op) const {
294 
295  try {
296  return import_structure(BasicStructure<Site>(pos_path),
297  imported_name,
298  relaxation_properties,
299  best_assignment,
300  cart_op);
301  }
302  catch(const std::exception &ex) {
303  throw std::runtime_error(std::string("Could not successfully import structure ") + pos_path.string() + ":\n" + ex.what());
304  }
305 
306 
307  }
308 
309  //*******************************************************************************************
311  std::string &imported_name,
312  jsonParser &relaxation_properties,
313  std::vector<Index> &best_assignment,
314  Eigen::Matrix3d &cart_op) const {
315 
316  //Indices for Configuration index and permutation operation index
318 
319  ConfigDoF tconfigdof;
320  Lattice mapped_lat;
321  bool new_config_flag;
322  //std::vector<Index> best_assignment;
323  if(!struc_to_configdof(_struc,
324  tconfigdof,
325  mapped_lat,
326  best_assignment,
327  cart_op))
328  throw std::runtime_error("Structure is incompatible with PRIM.");
329 
330  relaxation_properties["best_mapping"]["basis_deformation"] = ConfigMapping::basis_cost(tconfigdof, _struc.basis.size());
331  relaxation_properties["best_mapping"]["lattice_deformation"] = ConfigMapping::strain_cost(_struc.lattice(), tconfigdof, _struc.basis.size());
332  relaxation_properties["best_mapping"]["volume_change"] = tconfigdof.deformation().determinant();
333 
334  Index import_scel_index = primclex().add_supercell(mapped_lat), import_config_index;
335 
336  Configuration import_config(primclex().get_supercell(import_scel_index), jsonParser(), tconfigdof);
337 
338  if(m_strict_flag) {
339  it_canon = primclex().get_supercell(import_scel_index).permute_begin();
340  new_config_flag = primclex().get_supercell(import_scel_index).add_canon_config(import_config, import_config_index);
341  imported_name = primclex().get_supercell(import_scel_index).get_config(import_config_index).name();
342  }
343  else {
344  it_canon = primclex().get_supercell(import_scel_index).permute_begin();
345  new_config_flag = primclex().get_supercell(import_scel_index).add_config(import_config, import_config_index, it_canon);
346  imported_name = primclex().get_supercell(import_scel_index).get_config(import_config_index).name();
347  }
348 
349  relaxation_properties["best_mapping"]["relaxation_deformation"] = it_canon.sym_op().matrix() * tconfigdof.deformation() * it_canon.sym_op().matrix().transpose();
350 
351  cart_op = it_canon.sym_op().matrix() * cart_op;
352 
353  // compose permutations
354  std::vector<Index>tperm = it_canon.combined_permute().permute(best_assignment);
355 
356  //copy non-vacancy part of permutation into best_assignment
357  best_assignment.resize(_struc.basis.size());
358  Index num_atoms = _struc.basis.size();
359  std::copy_if(tperm.cbegin(), tperm.cend(),
360  best_assignment.begin(),
361  [num_atoms](Index i) {
362  return i < num_atoms;
363  });
364  return new_config_flag;
365 
366  }
367 
368  //*******************************************************************************************
370  ConfigDoF &mapped_configdof,
371  Lattice &mapped_lat) const {
372  std::vector<Index> t_assign;
373  Eigen::Matrix3d t_op;
374  return struc_to_configdof(struc, mapped_configdof, mapped_lat, t_assign, t_op);
375  }
376  //*******************************************************************************************
378  ConfigDoF &mapped_configdof,
379  Lattice &mapped_lat,
380  std::vector<Index> &best_assignment,
381  Eigen::Matrix3d &cart_op,
382  double best_cost /*=1e20*/) const {
383 
384  bool valid_mapping(false);
385  // If structure's lattice is a supercell of the primitive lattice, then import as ideal_structure
386  if(!m_robust_flag && struc.lattice().is_supercell_of(primclex().get_prim().lattice(), m_tol)) {
387  valid_mapping = ideal_struc_to_configdof(struc,
388  mapped_configdof,
389  mapped_lat,
390  best_assignment,
391  cart_op);
392  //std::cout << "valid_mapping is " << valid_mapping << "\n";
393  valid_mapping = valid_mapping && ConfigMapping::basis_cost(mapped_configdof, struc.basis.size()) < (10 * m_tol);
394  }
395 
396  // If structure's lattice is not a supercell of the primitive lattice, then import as deformed_structure
397  if(!valid_mapping) { // if not a supercell or m_robust_flag=true, treat as deformed
398  valid_mapping = deformed_struc_to_configdof(struc,
399  mapped_configdof,
400  mapped_lat,
401  best_assignment,
402  cart_op,
403  best_cost);
404  }
405  return valid_mapping;
406  }
407 
408  //*******************************************************************************************
409  /*
410  * Given a structure and a primclex, find a perfect supercell of the prim that is equivalent to structure's lattice
411  * and then try to map the structure's basis onto that supercell
412  *
413  * Returns false if no mapping is possible, or if the lattice is not ideal
414  *
415  * What this does NOT do:
416  * -Check if the imported Structure is the same as one in a smaller Supercell
417  *
418  */
419  //*******************************************************************************************
421  ConfigDoF &mapped_configdof,
422  Lattice &mapped_lat,
423  std::vector<Index> &best_assignment,
424  Eigen::Matrix3d &cart_op) const {
425  // Lattice::is_supercell_of() isn't very smart right now, and will return false if the two lattices differ by a rigid rotation
426  // In the future this may not be the case, so we will assume that struc may be rigidly rotated relative to prim
427  Eigen::Matrix3d trans_mat;
428  if(!struc.lattice().is_supercell_of(primclex().get_prim().lattice(), trans_mat, m_tol)) {
429  /*std::cerr << "CRITICAL ERROR: In ideal_struc_to_configdof(), primitive structure does not tile the provided\n"
430  << " superstructure. Please use deformed_struc_to_configdof() instead.\n"
431  << " Exiting...\n";
432  */
433  return false;
434  }
435  BasicStructure<Site> tstruc(struc);
436 
437  // We know struc.lattice() is a supercell of the prim, now we have to reorient 'struc' to match canonical lattice vectors
438  mapped_lat = canonical_equivalent_lattice(Lattice(primclex().get_prim().lattice().lat_column_mat() * trans_mat), primclex().get_prim().point_group(), m_tol);
439  Supercell scel(&primclex(), mapped_lat);
440 
441  // note: trans_mat gets recycled here
442  mapped_lat.is_supercell_of(struc.lattice(), primclex().get_prim().point_group(), trans_mat, m_tol);
443  tstruc.set_lattice(Lattice(tstruc.lattice().lat_column_mat()*trans_mat), CART);
444 
445  //cart_op goes from imported coordinate system to ideal (PRIM) coordinate system
446  cart_op = mapped_lat.lat_column_mat() * tstruc.lattice().inv_lat_column_mat();
447  tstruc.set_lattice(mapped_lat, FRAC);
448  if(!m_rotate_flag) {
449  cart_op = Eigen::Matrix3d::Identity(3, 3);
450  }
452  tstruc,
453  cart_op.transpose(),//cart_op.transpose() is deformation in this case
454  mapped_configdof,
455  best_assignment,
456  true,
457  m_tol);
458  }
459 
460  //*******************************************************************************************
461  /*
462  * Given a structure and a primclex, iterate over many supercells of the prim and for ideal supercells that
463  * nearly match the structure's lattice, try to map the structure's basis onto that supercell
464  *
465  * This process iteratively improves the mapping cost function -> total_cost = w*lattice_cost + (1-w)*basis_cost
466  * where 'w' is the lattice-cost weight parameter. It's unlikely that there is an objective way to choose 'w'
467  * without information regarding the physics of the system (e.g., where is the extremum of the energy barrier
468  * when going from a particular ideal configuration to the specified deformed structure)
469  *
470  * Returns false if no mapping is possible (which should only happen if the passed structure has a composition
471  * that cannot be realized in the system described by the primclex).
472  *
473  * What this does NOT do:
474  * -Check if the imported Structure is the same as one in a smaller Supercell
475  *
476  */
477  //*******************************************************************************************
479  ConfigDoF &mapped_configdof,
480  Lattice &mapped_lat,
481  std::vector<Index> &best_assignment,
482  Eigen::Matrix3d &cart_op,
483  double best_cost /*=1e20*/) const {
484 
485  //squeeze lattice_weight into [0,1] if necessary
486  double lw = m_lattice_weight;
487  double bw = 1.0 - lw;
488 
489 
490  std::vector<Index> assignment;
491  //Add new Supercell if it doesn't exist already. Use primitive point group to check for equivalence and
492  //store transformation matrix
493  Eigen::Matrix3d deformation;
494  double num_atoms = double(struc.basis.size());
495  int min_vol, max_vol;
496 
497  mapped_configdof.clear();
498  if(m_fixed_components.size() > 0) {
499  std::string tcompon = m_fixed_components[0].first;
500  int ncompon(0);
501  for(Index i = 0; i < struc.basis.size(); i++) {
502  if(struc.basis[i].occ_name() == tcompon)
503  ncompon++;
504  }
505  min_vol = ncompon / int(m_fixed_components[0].second);
506  max_vol = min_vol;
507  }
508  else {
509  // Try to narrow the range of supercell volumes -- the best bounds are obtained from
510  // the convex hull of the end-members, but we need to wait for improvements to convex hull
511  // routines
512 
513  int max_n_va = primclex().get_prim().max_possible_vacancies();
514  double max_va_frac_limit = double(max_n_va) / double(primclex().get_prim().basis.size());
515  double t_min_va_frac = min(min_va_frac(), max_va_frac_limit);
516  double t_max_va_frac = min(max_va_frac(), max_va_frac_limit);
517 
518  // min_vol assumes min number vacancies -- best case scenario
519  min_vol = ceil((num_atoms / (double(primclex().get_prim().basis.size())) * 1. - t_min_va_frac) - m_tol);
520 
521  // This is for the worst case scenario -- lots of vacancies
522  max_vol = ceil(num_atoms / (double(primclex().get_prim().basis.size()) * (1.0 - t_max_va_frac)) - m_tol);
523 
524  if(t_max_va_frac > TOL) {
525  //Nvol is rounded integer volume-- assume that answer is within 30% of this volume, and use it to tighten our bounds
526  int Nvol = round(std::abs(struc.lattice().vol() / primclex().get_prim().lattice().vol()));
527  int new_min_vol = min(max_vol, max(round((1.0 - m_max_volume_change) * double(Nvol)), min_vol));
528  int new_max_vol = max(min_vol, min(round((1.0 + m_max_volume_change) * double(Nvol)), max_vol));
529  max_vol = new_max_vol;
530  min_vol = new_min_vol;
531  }
532  }
533 
534  min_vol = max(min_vol, 1);
535  max_vol = max(max_vol, 1);
536 
537 
538  Eigen::Matrix3d ttrans_mat, tF, rotF;
539 
540  double strain_cost(1e10), basis_cost(1e10), tot_cost;//, best_strain_cost, best_basis_cost;
541  ConfigDoF tdof;
542  BasicStructure<Site> tstruc(struc);
543  Lattice tlat;
544 
545  // First pass: Find a reasonable upper bound
546  for(Index i_vol = min_vol; i_vol <= max_vol; i_vol++) {
547  tlat = ConfigMapping::find_nearest_super_lattice(primclex().get_prim().lattice(),
548  struc.lattice(),
550  tF,
551  ttrans_mat,
552  _lattices_of_vol(i_vol),
553  m_tol);
554  strain_cost = lw * LatticeMap::calc_strain_cost(tF, struc.lattice().vol() / max(num_atoms, 1.));
555 
556  if(best_cost < strain_cost) {
557  continue;
558  }
559 
560  tstruc = struc;
561 
562  //make tstruc an un-rotated, un-strained version of struc
563  tstruc.set_lattice(Lattice(tlat.lat_column_mat()*ttrans_mat), FRAC);
564  tstruc.set_lattice(tlat, CART);
565  rotF = tF;
566  if(m_rotate_flag) {
568  }
569 
570  Supercell scel(&primclex(), tlat);
572  tstruc,
573  rotF,
574  tdof,
575  assignment,
576  true,
577  m_tol))
578  continue;
579  basis_cost = bw * ConfigMapping::basis_cost(tdof, struc.basis.size());
580  tot_cost = strain_cost + basis_cost;
581 
582  if(tot_cost < best_cost) {
583  best_cost = tot_cost - m_tol;
584  swap(best_assignment, assignment);
585 
586  cart_op = rotF * tF.inverse();
587 
588  swap(mapped_configdof, tdof);
589 
590  mapped_lat = tlat;
591  }
592  }
593 
594 
595  //Second pass: Find the absolute best mapping
596  for(Index i_vol = min_vol; i_vol <= max_vol; i_vol++) {
597  //std::cout << " vol = " << i_vol << "\n";
598  const std::vector<Lattice> &lat_vec = _lattices_of_vol(i_vol);
599 
600  for(auto it = lat_vec.cbegin(); it != lat_vec.cend(); ++it) {
602  *it,
603  best_cost,
604  mapped_configdof,
605  mapped_lat,
606  best_assignment,
607  cart_op))
608  break;
609  }
610  }
611 
612  //std::cout << "best_cost = " << best_cost << " best_strain_cost = " << best_strain_cost << " best_basis_cost = " << best_basis_cost << "\n";
613  if(best_cost > 1e9) {
614  //std::cerr << "WARNING: In Supercell::import_deformed_structure(), no successful mapping was found for Structure " << src << "\n"
615  // << " This Structure may be incompatible with the ideal crystal specified by the PRIM file. \n";
616  return false;
617  }
618 
619  // If mapped_configdof is empty, it means that nothing better than best_cost was found
620  return mapped_configdof.size() > 0;
621  }
622 
623  //*******************************************************************************************
625  const Lattice &imposed_lat,
626  double &best_cost,
627  ConfigDoF &mapped_configdof,
628  Lattice &mapped_lat,
629  std::vector<Index> &best_assignment,
630  Eigen::Matrix3d &cart_op) const {
631  double strain_cost, basis_cost, tot_cost;
632  ConfigDoF tdof;
633  BasicStructure<Site> tstruc(struc);
634  Eigen::Matrix3d tF, rotF;
635  std::vector<Index> assignment;
636  Supercell scel(&primclex(), imposed_lat);
637 
638  double lw = m_lattice_weight;
639  double bw = 1.0 - lw;
640  double num_atoms = double(struc.basis.size());
641  //Determine best mapping for this supercell
642 
643  //Initialize with simplest mapping onto supercell 'i', so that we don't change the crystal setting unnecessarily
644  tF = struc.lattice().lat_column_mat() * imposed_lat.inv_lat_column_mat();
645 
646  strain_cost = lw * LatticeMap::calc_strain_cost(tF, struc.lattice().vol() / max(num_atoms, 1.));
647 
648  // If simplest mapping seems viable, check it further
649  if(strain_cost < best_cost) {
650  tstruc = struc;
651  tstruc.set_lattice(imposed_lat, FRAC);
652  rotF = tF;
653  if(m_rotate_flag) {
655  }
656 
658  tstruc,
659  rotF,
660  tdof,
661  assignment,
662  true,
663  m_tol))
664  return false;
665 
666  basis_cost = bw * ConfigMapping::basis_cost(tdof, struc.basis.size());
667  //std::cout << "\n**Starting strain_cost = " << strain_cost << "; and basis_cost = " << basis_cost << " TOTAL: " << strain_cost + basis_cost << "\n";
668  tot_cost = strain_cost + basis_cost;
669 
670  //std::cout << " scel.name = " << scel.get_name() << " simple map: strain_cost " << strain_cost << " best_cost " << best_cost << " tot_cost " << tot_cost << "\n";
671  if(tot_cost < best_cost) {
672  best_cost = tot_cost - m_tol;
673  //best_strain_cost = strain_cost;
674  //best_basis_cost = basis_cost;
675  swap(best_assignment, assignment);
676  cart_op = rotF * tF.inverse();
677  //best_trans = Matrix3<double>::identity();
678  //std::cout << "tF is:\n" << tF << "\n and N is:\n" << best_trans << "\n";
679  swap(mapped_configdof, tdof);
680  mapped_lat = imposed_lat;
681  }
682  } // Done checking simplest mapping
683 
684  // If the simplest mapping is best, we have avoided a lot of extra work, but we still need to check for
685  // non-trivial mappings that are better than both the simplest mapping and the best found mapping
686  LatticeMap strainmap(imposed_lat, struc.lattice(), round(num_atoms), m_tol, 1);
687  strain_cost = lw * strainmap.strain_cost();
688  if(best_cost < strain_cost)
689  strain_cost = lw * strainmap.next_mapping_better_than(best_cost).strain_cost();
690 
691  while(strain_cost < best_cost) { // only enter loop if there's a chance of improving on current best
692 
693  tstruc = struc;
694  // We modify the deformed structure so that its lattice is a deformed version of the nearest ideal lattice
695  // Don't need matrixN if we use set_lattice(CART), because matrixF depends on matrixN implicitly
696  tstruc.set_lattice(Lattice(imposed_lat.lat_column_mat()*strainmap.matrixN()), FRAC);
697  tstruc.set_lattice(imposed_lat, CART);
698  tF = strainmap.matrixF();
699  rotF = tF;
700  if(m_rotate_flag) {
702  }
703 
705  tstruc,
706  rotF,
707  tdof,
708  assignment,
709  true,
710  m_tol)) {
711  return false;
712  //no longer unexpected
713  //throw std::runtime_error("Unexpected error in deformed_struc_to_config_dof(). This should never happen!\n");
714  }
715  basis_cost = bw * ConfigMapping::basis_cost(tdof, struc.basis.size());
716  //std::cout << "New strain_cost = " << strain_cost << "; and basis_cost = " << basis_cost << " TOTAL: " << strain_cost + basis_cost << "\n";
717  //std::cout << " Compare -> best_cost = " << best_cost << "\n";
718 
719  tot_cost = strain_cost + basis_cost;
720  //std::cout << " complex map: best_cost " << best_cost << " strain_cost " << strain_cost << " tot_cost " << tot_cost << "\n";
721 
722  if(tot_cost < best_cost) {
723  //std::cout << "Old best_trans, with cost " << best_cost << ":\n" << best_trans << "\n";
724  best_cost = tot_cost - m_tol;
725  swap(best_assignment, assignment);
726  //best_strain_cost = strain_cost;
727  //best_basis_cost = basis_cost;
728  cart_op = rotF * tF.inverse();
729  //best_trans = strainmap.matrixN();
730  //std::cout << "New best_trans, with cost " << best_cost << ":\n" << best_trans << "\n";
731  swap(mapped_configdof, tdof);
732  mapped_lat = imposed_lat;
733  }
734  // This finds first decomposition:
735  // struc.lattice() = deformation*(supercell_list[import_scel_index].get_real_super_lattice())*equiv_mat
736  // that has cost function less than best_cost
737  strain_cost = lw * strainmap.next_mapping_better_than(best_cost).strain_cost();
738  }
739  return true;
740  }
741 
742  //*******************************************************************************************
743  const std::vector<Lattice> &ConfigMapper::_lattices_of_vol(Index prim_vol) const {
744  if(!valid_index(prim_vol)) {
745  throw std::runtime_error("Cannot enumerate lattice of volume " + std::to_string(prim_vol) + ", which is out of bounds.\n");
746  }
747  auto it = m_superlat_map.find(prim_vol);
748  if(it != m_superlat_map.end())
749  return it->second;
750 
751  std::vector<Lattice> lat_vec;
752  SupercellEnumerator<Lattice> enumerator(
753  primclex().get_prim().lattice(),
755  ScelEnumProps(prim_vol, prim_vol + 1));
756 
757  //std::cout << "min_vol is " << min_vol << "max_vol is " << max_vol << "\n";
758  for(auto it = enumerator.begin(); it != enumerator.end(); ++it) {
759  //std::cout << "Enumeration step " << l++ << " best cost is " << best_cost << "\n";
760  lat_vec.push_back(canonical_equivalent_lattice(*it, primclex().get_prim().point_group(), m_tol));
761  }
762 
763  return m_superlat_map[prim_vol] = std::move(lat_vec);
764 
765  }
766 
767  //****************************************************************************************************************
768 
769  namespace ConfigMap_impl {
770 
771  //****************************************************************************************************************
772  // Assignment Problem methods
773  //****************************************************************************************************************
774  /*
775  * Finding the cost_matrix given the relaxed structure
776  * This will always return a square matrix with the extra elements
777  * reflecting the vacancies specified in the ideal supercell.
778  * Costs are calculated in context of the real_super_lattice.
779  */
780  //****************************************************************************************************************
781 
782  bool calc_cost_matrix(const Supercell &scel,
783  const BasicStructure<Site> &rstruc,
784  const Coordinate &trans,
785  const Eigen::Matrix3d &metric,
786  Eigen::MatrixXd &cost_matrix) {
787 
788  if(rstruc.basis.size() > scel.num_sites())
789  return false;
790  double inf = 10E10;
791  //if(cost_matrix.rows()!=scel.num_sites() || cost_matrix.cols()!=scel.num_sites())
792  cost_matrix = Eigen::MatrixXd::Constant(scel.num_sites(), scel.num_sites(), inf);
793  Index inf_counter;
794  // loop through all the sites of the structure
795  Index j = 0;
796  for(; j < rstruc.basis.size(); j++) {
797  Coordinate current_relaxed_coord(rstruc.basis[j].frac(), scel.get_real_super_lattice(), FRAC);
798  current_relaxed_coord.cart() += trans.cart();
799  // loop through all the sites in the supercell
800  inf_counter = 0;
801  for(Index i = 0; i < scel.num_sites(); i++) {
802 
803  // Check if relaxed atom j is allowed on site i
804  // If so, populate cost_matrix normally
805  if(scel.get_prim().basis[scel.get_b(i)].contains(rstruc.basis[j].occ_name())) {
806  cost_matrix(i, j) = scel.coord(i).min_dist2(current_relaxed_coord, metric);
807  }
808  // If not, set cost_matrix (i,j) = inf
809  else {
810  cost_matrix(i, j) = inf;
811  inf_counter++;
812  }
813  }
814  if(inf_counter == scel.num_sites()) {
815  //std:: cerr << "Bail at 1\n";
816  return false;
817  }
818  }
819 
820 
821  for(; j < scel.num_sites(); j++) {
822  inf_counter = 0;
823  for(Index i = 0; i < scel.num_sites(); i++) {
824 
825  // Check if vacancies are allowed at each position in the supercell
826  if(scel.get_prim().basis[scel.get_b(i)].contains("Va")) {
827  cost_matrix(i, j) = 0;
828  }
829  else {
830  cost_matrix(i, j) = inf;
831  inf_counter++;
832  }
833  }
834  if(inf_counter == scel.num_sites()) {
835  //std:: cerr << "Bail at 2\n";
836  return false;
837  }
838  }
839 
840  // JCT: I'm not sure if there's an easy way to check if the cost matrix is viable in all cases
841  // Some of the simpler checks I could think of failed for edge cases with vacancies.
842  // If we return an invalid cost matrix, the Hungarian routines will detect that it is invalid,
843  // so maybe there's no point in doing additional checks here.
844  return true;
845  }
846 
847  //****************************************************************************************************************
848  bool calc_cost_matrix(const Configuration &config,
849  const BasicStructure<Site> &rstruc,
850  const Coordinate &trans,
851  const Eigen::Matrix3d &metric,
852  Eigen::MatrixXd &cost_matrix) {
853 
854 
855  double inf = 10E10;
856  const Supercell &scel(config.get_supercell());
857  //if(cost_matrix.rows()!=scel.num_sites() || cost_matrix.cols()!=scel.num_sites())
858  cost_matrix = Eigen::MatrixXd::Constant(scel.num_sites(), scel.num_sites(), inf);
859  Index inf_counter;
860  // loop through all the sites of the structure
861  Index j;
862  for(j = 0; j < rstruc.basis.size(); j++) {
863  Coordinate current_relaxed_coord(rstruc.basis[j].frac(), scel.get_real_super_lattice(), FRAC);
864  current_relaxed_coord.cart() += trans.cart();
865  // loop through all the sites in the supercell
866  inf_counter = 0;
867  for(Index i = 0; i < scel.num_sites(); i++) {
868 
869  // Check if relaxed atom j is allowed on site i
870  // If so, populate cost_matrix normally
871  if(config.get_mol(i).name == rstruc.basis[j].occ_name()) {
872  cost_matrix(i, j) = scel.coord(i).min_dist2(current_relaxed_coord, metric);
873  }
874  // If not, set cost_matrix (i,j) = inf
875  else {
876  cost_matrix(i, j) = inf;
877  inf_counter++;
878  }
879  }
880  if(inf_counter == scel.num_sites()) {
881  //std:: cerr << "Bail at 1\n";
882  return false;
883  }
884  }
885 
886 
887  for(; j < scel.num_sites(); j++) {
888  inf_counter = 0;
889  for(Index i = 0; i < scel.num_sites(); i++) {
890 
891  // Check if vacancies are allowed at each position in the supercell
892  if(config.get_mol(i).name == "Va") {
893  cost_matrix(i, j) = 0;
894  }
895  else {
896  cost_matrix(i, j) = inf;
897  inf_counter++;
898  }
899  }
900  if(inf_counter == scel.num_sites()) {
901  //std:: cerr << "Bail at 2\n";
902  return false;
903  }
904  }
905 
906  // JCT: I'm not sure if there's an easy way to check if the cost matrix is viable in all cases
907  // Some of the simpler checks I could think of failed for edge cases with vacancies.
908  // If we return an invalid cost matrix, the Hungarian routines will detect that it is invalid,
909  // so maybe there's no point in doing additional checks here.
910  return true;
911  }
912 
913  //***************************************************************************************************
914  // Options:
915  //
916  // translate_flag = true means that the rigid-translations are removed. (typically this option should be used)
917  //
918  // translate_flag = false means that rigid translations are not considered. (probably don't want to use this since structures should be considered equal if they are related by a rigid translation).
919  //
920  bool struc_to_configdof(const Supercell &scel,
921  BasicStructure<Site> rstruc,
922  ConfigDoF &config_dof,
923  std::vector<Index> &best_assignments,
924  const bool translate_flag,
925  const double _tol) {
927  // un-deform rstruc
928  rstruc.set_lattice(scel.get_real_super_lattice(), FRAC);
929  return preconditioned_struc_to_configdof(scel, rstruc, deformation, config_dof, best_assignments, translate_flag, _tol);
930  }
931 
932  //***************************************************************************************************
933  // Options:
934  //
935  // translate_flag = true means that the rigid-translations are removed. (typically this option should be used)
936  //
937  // translate_flag = false means that rigid translations are not considered. (probably don't want to use this since structures should be considered equal if they are related by a rigid translation).
938  //
939  bool struc_to_configdof(const Configuration &config,
940  BasicStructure<Site> rstruc,
941  ConfigDoF &config_dof,
942  std::vector<Index> &best_assignments,
943  const bool translate_flag,
944  const double _tol) {
945  const Lattice &mapped_lat(config.get_supercell().get_real_super_lattice());
946  Eigen::Matrix3d deformation = rstruc.lattice().lat_column_mat() * mapped_lat.inv_lat_column_mat();
947  // un-deform rstruc
948  rstruc.set_lattice(mapped_lat, FRAC);
949  return preconditioned_struc_to_configdof(config, rstruc, deformation, config_dof, best_assignments, translate_flag, _tol);
950  }
951 
952  //***************************************************************************************************
953  // Options:
954  //
955  // translate_flag = true means that the rigid-translations are removed. (typically this option should be used)
956  //
957  // translate_flag = false means that rigid translations are not considered. (probably don't want to use this since structures should be considered equal if they are related by a rigid translation).
958  //
960  const BasicStructure<Site> &rstruc,
961  const Eigen::Matrix3d &deformation,
962  ConfigDoF &config_dof,
963  std::vector<Index> &best_assignments,
964  const bool translate_flag,
965  const double _tol) {
966  //std::cout << "CONVERTING TO CONFIGDOF:\n";
967  //rstruc.print(std::cout);
968  //std::cout << std::endl;
969  // clear config_dof and set its deformation
970  config_dof.clear();
971 
972  config_dof.set_deformation(deformation);
973  Eigen::Matrix3d metric(deformation.transpose()*deformation);
974  //Initialize everything
975 
976  Eigen::MatrixXd cost_matrix;
977  std::vector<Index> optimal_assignments;
978  //BasicStructure<Site> best_ideal_struc(rstruc);
979  Coordinate best_trans(rstruc.lattice());
980  double min_mean = 10E10;
981 
982  // We want to get rid of translations.
983  // define translation such that:
984  // IDEAL = RELAXED + translation
985  // and use it when calculating cost matrix
986 
987  Index num_translations(1);
988 
989  if(rstruc.basis.size())
990  num_translations += scel.get_prim().basis.size();
991 
992  //std::cout << "num_translations is " << num_translations << "\n";
993  for(Index n = 0; n < num_translations; n++) {
994  double mean;
995 
996  //shift_struc has **ideal lattice**
997  //BasicStructure<Site> shift_struc(rstruc);
998 
999 
1000  if(n > 0 && !scel.get_prim().basis[n - 1].contains(rstruc.basis[0].occ_name()))
1001  continue;
1002 
1003  Coordinate translation(scel.get_prim().lattice());
1004 
1005  // Always try the non-translated case (n==0), in case it gives best result
1006  // Also try translating first basis atom onto each chemically compatible site of PRIM (n>0)
1007  if(n > 0) {
1008  translation.cart() = scel.coord((n - 1) * scel.volume()).const_cart() - rstruc.basis[0].const_cart();
1009  translation.voronoi_within();
1010  }
1011 
1012  if(!ConfigMap_impl::calc_cost_matrix(scel, rstruc, translation, metric, cost_matrix)) {
1014  return false;
1015  }
1016 
1017  // The mapping routine is called here
1018  mean = hungarian_method(cost_matrix, optimal_assignments, _tol);
1019 
1020  // if optimal_assignments is smaller than rstruc.basis.size(), then rstruc is incompattible with supercell
1021  // (optimal_assignments.size()==0 if the hungarian routine detects an incompatibility)
1022  if(optimal_assignments.size() < rstruc.basis.size()) {
1023  return false;
1024  }
1025 
1026 
1027  // add small penalty (~_tol) for larger translation distances, so that shortest equivalent translation is used
1028  mean += _tol * translation.const_cart().norm() / 10.0;
1029 
1030  if(mean < min_mean) {
1031  //std::cout << "mean " << mean << " is better than min_mean " << min_mean <<"\n";
1032 
1033  // new best
1034  swap(best_assignments, optimal_assignments);
1035 
1036  // best shifted structure
1037  best_trans.cart() = translation.cart();
1038 
1039  // update the minimum mean costs
1040  min_mean = mean;
1041  }
1042  }
1043 
1044  // Now we are filling up displacements
1045  //
1046  // Make zero_vector for special vacancy cases.
1047  Eigen::Vector3d zero_vector(0.0, 0.0, 0.0);
1048 
1049  // initialize displacement matrix with all zeros
1050  config_dof.set_displacement(ConfigDoF::displacement_matrix_t::Zero(3, scel.num_sites()));
1051 
1052  Eigen::Vector3d avg_disp(0, 0, 0);
1053 
1054  Coordinate disp_coord(rstruc.lattice());
1055 
1056  // Populate displacements given as the difference in the Coordinates
1057  // as described by best_assignments.
1058  for(Index i = 0; i < best_assignments.size(); i++) {
1059 
1060  // If we are dealing with a vacancy, its displacment must be zero.
1061  //if(best_assignments(i) >= rstruc.basis.size()) {
1062  // --DO NOTHING--
1063  //}
1064 
1065 
1066  // Using min_dist routine to calculate the displacement vector that corresponds
1067  // to the distance used in the Cost Matrix and Hungarian Algorithm
1068  // The method returns the displacement vector pointing from the
1069  // IDEAL coordinate to the RELAXED coordinate
1070  if(best_assignments[i] < rstruc.basis.size()) {
1071 
1072  Coordinate ideal_coord(scel.coord(i).frac(), rstruc.lattice(), FRAC);
1073 
1074  (rstruc.basis[best_assignments[i]] + best_trans).min_dist(ideal_coord, disp_coord);
1075  //std::cout << "min_dist" << std::endl;
1076  //std::cout << rstruc.basis[optimal_assignments(i)].min_dist(pos_coord, disp_coord);
1077  config_dof.disp(i) = disp_coord.const_cart();
1078 
1079  avg_disp += config_dof.disp(i);
1080  }
1081  }
1082 
1083  avg_disp /= max(double(rstruc.basis.size()), 1.);
1084 
1085 
1086  // End of filling displacements
1087 
1088 
1089  // Make the assignment bitstring
1090  //
1091  // Loop through all supercell sites
1092  config_dof.set_occupation(Array<int>(scel.num_sites()));
1093  std::string rel_basis_atom;
1094  for(Index i = 0; i < best_assignments.size(); i++) {
1095  // subtract off average displacement
1096  if(best_assignments[i] < rstruc.basis.size()) {
1097  config_dof.disp(i) -= avg_disp;
1098  // suppress small ugly numbers.
1099  for(Index j = 0; j < 3; j++) {
1100  if(almost_zero(config_dof.disp(i)[j], 1e-8))
1101  config_dof.disp(i)[j] = 0;
1102  }
1103 
1104  //Record basis atom
1105  rel_basis_atom = rstruc.basis[best_assignments[i]].occ_name();
1106  }
1107  else {
1108  // Any value of the assignment vector larger than the number
1109  // of sites in the relaxed structure is by construction
1110  // specified as a vacancy.
1111  rel_basis_atom = "Va";
1112  }
1113 
1114  // set occupant and check for errors
1115  if(!scel.get_prim().basis[scel.get_b(i)].contains(rel_basis_atom, config_dof.occ(i))) {
1116  //std::cout << "best_assignments is " << best_assignments << "\n";
1117  //std::cout << "at site " << i << " corresponding to basis " << scel.get_b(i) << " attempting to assign type " << rel_basis_atom << "\n";
1118  //std::cout << "Cost Matrix is \n" << cost_matrix << "\n";
1119  //std::cerr << "CRITICAL ERROR: In Supercell::struc_to_configdof atoms of relaxed/custom structure are incompatible\n"
1120  // << " with the number or type of atomic species allowed in PRIM. Exiting...\n";
1121  //exit(1);
1122 
1123  return false;
1124  }
1125  }
1126 
1127  return true;
1128  }
1129 
1130 
1131 
1132  //***************************************************************************************************
1133  // Options:
1134  //
1135  // translate_flag = true means that the rigid-translations are removed. (typically this option should be used)
1136  //
1137  // translate_flag = false means that rigid translations are not considered. (probably don't want to use this since structures should be considered equal if they are related by a rigid translation).
1138  //
1140  const BasicStructure<Site> &rstruc,
1141  const Eigen::Matrix3d &deformation,
1142  ConfigDoF &config_dof,
1143  std::vector<Index> &best_assignments,
1144  const bool translate_flag,
1145  const double _tol) {
1146 
1147  const Supercell &scel(config.get_supercell());
1148 
1149  // clear config_dof and set its deformation
1150  config_dof.clear();
1151 
1152  config_dof.set_deformation(deformation);
1153  Eigen::Matrix3d metric(deformation.transpose()*deformation);
1154  //Initialize everything
1155 
1156  Eigen::MatrixXd cost_matrix;
1157  std::vector<Index> optimal_assignments;
1158  //BasicStructure<Site> best_ideal_struc(rstruc);
1159  Coordinate best_trans(rstruc.lattice());
1160 
1161  double min_mean = 10E10;
1162 
1163  // We want to get rid of translations.
1164  // define translation such that:
1165  // IDEAL = RELAXED + translation
1166  // and use it when calculating cost matrix
1167 
1168  Index num_translations(1);
1169 
1170  num_translations += rstruc.basis.size();
1171 
1172  //num_translations = rstruc.basis.size();
1173  //std::cout << "num_translations is " << num_translations << "\n";
1174  for(Index n = 0; n < num_translations; n++) {
1175  double mean;
1176 
1177  if(n > 0 && config.get_mol(0).name != rstruc.basis[n - 1].occ_name())
1178  continue;
1179 
1180  Coordinate translation(scel.get_real_super_lattice());
1181 
1182  // Always try the non-translated case (n==0), in case it gives best result
1183  // Also try translating first basis atom onto each chemically compatible site of PRIM (n>0)
1184  if(n > 0) {
1185  translation.cart() = scel.coord(0).const_cart() - rstruc.basis[n - 1].const_cart();
1186  translation.voronoi_within();
1187  }
1188 
1189  if(!ConfigMap_impl::calc_cost_matrix(config, rstruc, translation, metric, cost_matrix)) {
1190  //std::cerr << "In Supercell::struc_to_config. Cannot construct cost matrix." << std::endl;
1191  //std::cerr << "This message is probably OK, if you are using translate_flag == true." << std::endl;
1192  //continue;
1193  return false;
1194  }
1195 
1196  // The mapping routine is called here
1197  mean = hungarian_method(cost_matrix, optimal_assignments, _tol);
1198 
1199  // if optimal_assignments is smaller than rstruc.basis.size(), then rstruc is incompattible
1200  // with the supercell (optimal_assignments.size()==0 if the hungarian routine detects an incompatibility)
1201  if(optimal_assignments.size() < rstruc.basis.size()) {
1202  return false;
1203  }
1204 
1205  //std::cout << "mean is " << mean << " and stddev is " << stddev << "\n";
1206  // add small penalty (~_tol) for larger translation distances, so that shortest equivalent translation is used
1207  mean += _tol * translation.const_cart().norm() / 10.0;
1208  if(mean < min_mean) {
1209  //std::cout << "mean " << mean << " is better than min_mean " << min_mean <<"\n";
1210 
1211  // new best
1212  swap(best_assignments, optimal_assignments);
1213 
1214  // best shifted structure
1215  best_trans = translation;
1216 
1217  // update the minimum mean costs
1218  min_mean = mean;
1219  }
1220  }
1221 
1222  // Now we are filling up displacements
1223  //
1224  // Make zero_vector for special vacancy cases.
1225  Eigen::Vector3d zero_vector(0.0, 0.0, 0.0);
1226 
1227  // initialize displacement matrix with all zeros
1228  config_dof.set_displacement(ConfigDoF::displacement_matrix_t::Zero(3, scel.num_sites()));
1229 
1230  Eigen::Vector3d avg_disp(0, 0, 0);
1231 
1232  Coordinate disp_coord(rstruc.lattice());
1233 
1234  // Populate displacements given as the difference in the Coordinates
1235  // as described by best_assignments.
1236  for(Index i = 0; i < best_assignments.size(); i++) {
1237 
1238  // If we are dealing with a vacancy, its displacment must be zero.
1239  //if(best_assignments(i) >= rstruc.basis.size()) {
1240  // --DO NOTHING--
1241  //}
1242 
1243 
1244  // Using min_dist routine to calculate the displacement vector that corresponds
1245  // to the distance used in the Cost Matrix and Hungarian Algorithm
1246  // The method returns the displacement vector pointing from the
1247  // IDEAL coordinate to the RELAXED coordinate
1248  if(best_assignments[i] < rstruc.basis.size()) {
1249 
1250  Coordinate ideal_coord(scel.coord(i).frac(), rstruc.lattice(), FRAC);
1251 
1252  (rstruc.basis[best_assignments[i]] + best_trans).min_dist(ideal_coord, disp_coord);
1253  //std::cout << "min_dist" << std::endl;
1254  //std::cout << rstruc.basis[optimal_assignments(i)].min_dist(pos_coord, disp_coord);
1255  config_dof.disp(i) = disp_coord.const_cart();
1256 
1257  avg_disp += config_dof.disp(i);
1258  }
1259  }
1260 
1261  avg_disp /= max(double(rstruc.basis.size()), 1.);
1262 
1263 
1264  // End of filling displacements
1265 
1266 
1267  // Make the assignment bitstring
1268  //
1269  // Loop through all supercell sites
1270  config_dof.set_occupation(Array<int>(scel.num_sites()));
1271  std::string rel_basis_atom;
1272  for(Index i = 0; i < best_assignments.size(); i++) {
1273  // subtract off average displacement (non-vacant sites only)
1274  // Any value of the assignment vector larger than the number
1275  // of sites in the relaxed structure is by construction
1276  // specified as a vacancy.
1277  if(best_assignments[i] < rstruc.basis.size()) {
1278  config_dof.disp(i) -= avg_disp;
1279  // suppress small ugly numbers.
1280  for(Index j = 0; j < 3; j++) {
1281  if(almost_zero(config_dof.disp(i)[j], 1e-8))
1282  config_dof.disp(i)[j] = 0;
1283  }
1284  }
1285  config_dof.occ(i) = config.occ(i);
1286  }
1287 
1288  return true;
1289  }
1290 
1291  }
1292 }
const Configuration & get_config(Index i) const
Definition: Supercell.hh:287
Eigen::MatrixXd MatrixXd
bool deformed_struc_to_configdof_of_lattice(const BasicStructure< Site > &struc, const Lattice &imposed_lat, double &best_cost, ConfigDoF &mapped_configdof, Lattice &mapped_lat, std::vector< Index > &best_assignment, Eigen::Matrix3d &cart_op) const
Low-level routine to map a structure onto a ConfigDof assuming a specific Lattice, without assuming structure is ideal Will only identify mappings better than best_cost, and best_cost is updated to reflect cost of best mapping identified.
Coordinate coord(const UnitCellCoord &bijk) const
Definition: Supercell.cc:45
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:41
int & occ(Index i)
Definition: ConfigDoF.hh:61
ConfigMapper(NullInitializer)
Default construction not allowed – this constructor provides an override.
bool contains(const T &test_elem) const
Definition: Array.hh:281
void set_displacement(const displacement_matrix_t &_displacement)
Definition: ConfigDoF.cc:102
const int & occ(Index site_l) const
Occupant variable on site l.
Index size() const
Definition: Array.hh:145
Coordinate_impl::CartCoordinate cart()
Set Cartesian coordinate vector and update fractional coordinate vector.
Definition: Coordinate.hh:593
const Molecule & get_mol(Index site_l) const
Molecule on site l.
const SymGroup & point_group() const
Definition: Structure.cc:101
const Structure & get_prim() const
Definition: Supercell.cc:74
bool struc_to_configdof(const BasicStructure< Site > &_struc, ConfigDoF &mapped_configdof, Lattice &mapped_lat) const
Low-level routine to map a structure onto a ConfigDof.
bool is_equivalent(const Lattice &RHS, double tol) const
Are two lattices the same, even if they have different lattice vectors.
Definition: Lattice.cc:1002
Data structure for holding supercell enumeration properties.
double max_va_frac() const
Object copy_apply(const Transform &f, Object obj, Args &&...args)
bool preconditioned_struc_to_configdof(const Supercell &scel, const BasicStructure< Site > &rstruc, const Eigen::Matrix3d &deformation, ConfigDoF &config_dof, std::vector< Index > &best_assignment, const bool translate_flag, const double _tol)
Same as struc_to_configdof, except 'rstruc' is de-rotated and de-strained. Any deformation is instead...
double hungarian_method(const Eigen::MatrixXd &cost_matrix, std::vector< Index > &optimal_assignments, const double _tol)
Definition: CASM_math.cc:444
const std::vector< Lattice > & _lattices_of_vol(Index prim_vol) const
ReturnArray< T > permute(const Array< T > &before_array) const
Generate permuted copy of type-T Array.
Definition: Permutation.hh:126
const ConfigDoF & configdof() const
const Access the DoF
const_iterator end() const
A const iterator to the past-the-last volume.
const Lattice & get_real_super_lattice() const
Definition: Supercell.hh:267
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...
PermuteIterator inverse() const
A fake container of supercell matrices.
Definition: Enumerator.hh:407
Main CASM namespace.
Definition: complete.cpp:8
bool deformed_struc_to_configdof(const BasicStructure< Site > &_struc, ConfigDoF &mapped_config_dof, Lattice &mapped_lat, std::vector< Index > &best_assignment, Eigen::Matrix3d &cart_op, double best_cost=1e20) const
Low-level routine to map a structure onto a ConfigDof. Does not assume structure is ideal...
std::string to_string(ENUM val)
Return string representation of enum class.
Definition: EnumIO.hh:83
const Lattice & lattice() const
const double TOL
Represents a supercell of the primitive parent crystal structure.
Definition: Supercell.hh:37
const Eigen::Matrix3d & lat_column_mat() const
3x3 matrix with lattice vectors as its columne
Definition: Lattice.hh:104
void set_lattice(const Lattice &lattice, COORD_TYPE mode)
bool ideal_struc_to_configdof(const BasicStructure< Site > &struc, ConfigDoF &mapped_config_dof, Lattice &mapped_lat, std::vector< Index > &best_assignment, Eigen::Matrix3d &cart_op) const
Low-level routine to map a structure onto a ConfigDof if it is known to be ideal. ...
Index size() const
*** ACCESSORS ***
Definition: ConfigDoF.hh:53
const Eigen::Matrix3d & deformation() const
Definition: ConfigDoF.hh:85
PrimClex & primclex() const
void swap(ConfigDoF &A, ConfigDoF &B)
Definition: ConfigDoF.cc:195
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
Definition: SymGroup.hh:33
const matrix_type & matrix() const
Const access of entire cartesian symmetry matrix.
Definition: SymOp.hh:57
const Eigen::Matrix3d & inv_lat_column_mat() const
Inverse of Lattice::lat_column_mat() It is the transformation matrix 'C2F', such that f = C2F * c whe...
Definition: Lattice.hh:113
double strain_cost() const
Definition: LatticeMap.hh:35
const_iterator begin() const
A const iterator to the beginning volume, specify here how the iterator should jump through the enume...
permute_const_iterator permute_begin() const
Definition: Supercell.cc:179
const LatticeMap & best_strain_mapping() const
Definition: LatticeMap.cc:47
Represents cartesian and fractional coordinates.
Definition: Coordinate.hh:34
EigenIndex Index
For long integer indexing:
Index volume() const
Return number of primitive cells that fit inside of *this.
Definition: Supercell.hh:212
std::map< Index, std::vector< Lattice > > m_superlat_map
A container class for the different degrees of freedom a Configuration might have.
Definition: ConfigDoF.hh:27
Lattice canonical_equivalent_lattice(const Lattice &in_lat, const SymGroup &point_grp, double compare_tol)
Find the niggli, most standard oriented version of the given orbit (defined by the given SymGroup) of...
Definition: Niggli.cc:276
const DMatType & matrixF() const
Definition: LatticeMap.hh:41
Array< CoordType > basis
Lattice vectors that specifies periodicity of the crystal.
bool add_canon_config(const Configuration &config, Index &index)
Definition: Supercell.cc:590
Index max_possible_vacancies() const
Counts sites that allow vacancies.
bool add_config(const Configuration &config)
Definition: Supercell.cc:568
PrimClex is the top-level data structure for a CASM project.
Definition: PrimClex.hh:52
bool is_supercell_of(const Lattice &tile, Eigen::Matrix3d &multimat, double _tol=TOL) const
Matrix that relates two lattices (e.g., strain or slat)
Definition: Lattice.cc:655
T max(const T &A, const T &B)
Definition: CASM_math.hh:32
T min(const T &A, const T &B)
Definition: CASM_math.hh:25
std::string name() const
SCELV_A_B_C_D_E_F/i.
void set_deformation(const Eigen::Matrix3d &_deformation)
set_deformation sets ConfigDoF::has_deformation() to true
Definition: ConfigDoF.cc:119
double vol() const
Return signed volume of this lattice.
Definition: Lattice.hh:83
Index add_supercell(const Lattice &superlat)
Definition: PrimClex.cc:550
const DMatType & matrixN() const
Definition: LatticeMap.hh:38
Eigen::Matrix3d Matrix3d
PermuteIterator to_canonical() const
Returns the operation that applied to *this returns the canonical form.
jsonParser & put_obj()
Puts new empty JSON object.
Definition: jsonParser.hh:276
const Supercell & get_supercell(Index i) const
const Access supercell by index
Definition: PrimClex.cc:311
bool calc_cost_matrix(const Supercell &scel, const BasicStructure< Site > &rstruc, const Coordinate &trans, const Eigen::Matrix3d &metric, Eigen::MatrixXd &cost_matrix)
static double calc_strain_cost(const Eigen::Matrix3d &F, double relaxed_atomic_vol)
Definition: LatticeMap.cc:118
const displacement_matrix_t & displacement() const
Definition: ConfigDoF.hh:81
const Array< int > & occupation() const
Definition: ConfigDoF.hh:69
Coordinate_impl::FracCoordinate frac()
Set the fractional coordinate vector.
Definition: Coordinate.hh:581
bool struc_to_configdof(const Supercell &scel, BasicStructure< Site > rstruc, ConfigDoF &config_dof, std::vector< Index > &best_assignment, const bool translate_flag, const double _tol)
double basis_cost(const ConfigDoF &_dof, Index Nsites)
Calculate the basis cost function of a ConfigDoF as the mean-square displacement of its atoms...
double min_va_frac() const
Lattice find_nearest_super_lattice(const Lattice &prim_lat, const Lattice &relaxed_lat, const SymGroup &sym_group, Eigen::Matrix3d &trans_mat, Eigen::Matrix3d &deformation, double &best_cost, Index min_vol, Index max_vol, double _tol)
std::vector< std::pair< std::string, Index > > m_fixed_components
Supercell & get_supercell() const
Get the Supercell for this Configuration.
displacement_t disp(Index i)
Definition: ConfigDoF.hh:73
Index get_b(Index i) const
Definition: Supercell.hh:259
std::string name
Definition: Molecule.hh:112
static Matrix3d right_stretch_tensor(Matrix3d &C, Eigen::Vector3d &eigenvalues, Matrix3d &eigenvectors, const Matrix3d &F)
double min_dist2(const Coordinate &neighbor, const Eigen::Ref< const Eigen::Matrix3d > &metric) const
Finds same shift as min_dist but returns shift(CART).transpose()*metric*shift(CART) ...
Definition: Coordinate.cc:205
PermuteIterator from_canonical() const
Returns the operation that applied to the the canonical form returns *this.
void set_occupation(const Array< int > &_occupation)
Definition: ConfigDoF.cc:84
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
Index num_sites() const
Definition: Supercell.hh:220
Permutation combined_permute() const
Returns the combination of factor_group permutation and translation permutation.
int round(double val)
Definition: CASM_math.cc:6
bool valid_index(Index i)
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...
double strain_cost(const Lattice &relaxed_lat, const ConfigDoF &_dof, Index Nsites)
Calculate the strain cost function of a ConfigDoF using LatticeMap::calc_strain_cost() ...