CASM  1.1.0
A Clusters Approach to Statistical Mechanics
SimpleStructureTools.cc
Go to the documentation of this file.
2 
3 #include <stdexcept>
4 
10 #include "casm/external/Eigen/Core"
11 
12 namespace CASM {
13 namespace xtal {
14 namespace Local {
15 
17  Index mult) {
18  SimpleStructure::Info result;
19  result.resize(_info.size() * mult);
20 
21  for (Index i = 0; i < _info.size(); ++i)
22  result.coords.block(0, i * mult, 3, mult) =
23  _info.cart_coord(i).replicate(1, mult);
24 
25  for (auto const &p : _info.properties) {
26  result.properties.emplace(
27  p.first, Eigen::MatrixXd(p.second.rows(), mult * p.second.cols()));
28  for (Index i = 0; i < p.second.cols(); ++i)
29  result.coords.block(0, i * mult, p.second.rows(), mult) =
30  p.second.col(i).replicate(1, mult);
31  }
32 
33  Index l = 0;
34  for (Index b = 0; b < _info.size(); ++b) {
35  for (Index g = 0; g < mult; ++g) {
36  result.names[l++] = _info.names[b];
37  }
38  }
39  return result;
40 }
41 } // namespace Local
42 
43 //***************************************************************************
44 
45 SimpleStructure make_superstructure(Eigen::Ref<const Eigen::Matrix3i> const &_T,
46  SimpleStructure const &_sstruc) {
47  SimpleStructure superstructure;
48  superstructure.lat_column_mat = _sstruc.lat_column_mat * _T.cast<double>();
49  superstructure.properties = _sstruc.properties;
50 
51  auto all_lattice_points = make_lattice_points(_T.cast<long>());
52 
53  Index Nvol = all_lattice_points.size();
54 
55  superstructure.mol_info = Local::_replicate(_sstruc.mol_info, Nvol);
56  superstructure.atom_info = Local::_replicate(_sstruc.atom_info, Nvol);
57 
58  Index nm = _sstruc.mol_info.size();
59  Index na = _sstruc.atom_info.size();
60 
61  for (Index g = 0; g < Nvol; ++g) {
62  Eigen::Vector3d lattice_point_vector =
63  _sstruc.lat_column_mat * all_lattice_points[g].cast<double>();
64 
65  for (Index m = 0; m < nm; ++m) {
66  superstructure.mol_info.cart_coord(g + m * Nvol) += lattice_point_vector;
67  }
68  for (Index a = 0; a < na; ++a) {
69  superstructure.atom_info.cart_coord(g + a * Nvol) += lattice_point_vector;
70  }
71  }
72 
73  return superstructure;
74 }
75 
76 //***************************************************************************************************
77 
84 std::vector<Index> superstructure_basis_idx(
85  Eigen::Ref<const Eigen::Matrix3i> const &_T,
86  SimpleStructure const &_sstruc) {
87  auto all_lattice_points = make_lattice_points(_T.cast<long>());
88  Index Nvol = all_lattice_points.size();
89  std::vector<Index> basis_idx(_sstruc.atom_info.size() * Nvol, -1);
90  for (Index grid_idx = 0; grid_idx < Nvol; ++grid_idx) {
91  for (Index atom_idx = 0; atom_idx < _sstruc.atom_info.size(); ++atom_idx)
92  basis_idx[grid_idx + atom_idx * Nvol] = atom_idx;
93  }
94  return basis_idx;
95 }
96 
97 //***************************************************************************
98 
100  SimpleStructure result;
101  result.lat_column_mat = _struc.lattice().lat_column_mat();
102 
103  result.mol_info.coords.resize(3, _struc.basis().size());
104  result.mol_info.names.reserve(_struc.basis().size());
105  Eigen::VectorXi _mol_occ;
106  // For now, default to first occupant. In future we may decide
107  // to force user to pass mol_occ explicitly
108  _mol_occ.setZero(_struc.basis().size());
109  for (Index b = 0; b < _struc.basis().size(); ++b) {
110  result.mol_info.cart_coord(b) = _struc.basis()[b].const_cart();
111  result.mol_info.names.push_back(
112  _struc.basis()[b].occupant_dof()[_mol_occ[b]].name());
113  }
114  _atomize(result, _mol_occ, _struc);
115  return result;
116 }
117 
119  SimpleStructure const &_sstruc, std::vector<DoFKey> const &_all_dofs,
121  std::vector<std::vector<Molecule>> _allowed_occupants) {
122  std::map<DoFKey, DoFSet> global_dof;
123  std::map<DoFKey, SiteDoFSet> local_dof;
124  for (DoFKey const &dof : _all_dofs) {
125  if (AnisoValTraits(dof).global()) {
126  global_dof.emplace(dof, AnisoValTraits(dof));
127  } else {
128  local_dof.emplace(dof, AnisoValTraits(dof));
129  }
130  }
131 
132  auto const &info = _sstruc.info(mode);
133  if (_allowed_occupants.empty()) _allowed_occupants.resize(info.size());
134  for (Index i = 0; i < info.size(); ++i) {
135  if (_allowed_occupants[i].empty()) {
136  _allowed_occupants[i].push_back(Molecule::make_atom(info.names[i]));
137  }
138  if (_allowed_occupants[i].size() == 1) {
139  std::map<std::string, SpeciesAttribute> attr_map =
140  _allowed_occupants[i][0].attributes();
141  for (auto it = attr_map.begin(); it != attr_map.end(); ++it) {
142  if (local_dof.count(it->first)) {
143  auto er_it = it++;
144  attr_map.erase(er_it);
145  }
146  }
147 
148  for (auto const &prop : info.properties) {
149  if (local_dof.count(prop.first)) continue;
150 
151  if (prop.first == "disp") continue;
152 
153  if (!almost_zero(prop.second.col(i)))
154  attr_map.emplace(prop.first,
155  SpeciesAttribute(prop.first, prop.second.col(i)));
156  }
157  _allowed_occupants[i][0].set_attributes(attr_map);
158  }
159  }
160 
161  BasicStructure result(Lattice(_sstruc.lat_column_mat));
162  result.set_global_dofs(global_dof);
163  std::vector<Site> tbasis(info.size(), Site(result.lattice()));
164 
165  for (Index i = 0; i < info.size(); ++i) {
166  tbasis[i].cart() = info.cart_coord(i);
167  tbasis[i].set_allowed_occupants(std::move(_allowed_occupants[i]));
168  tbasis[i].set_dofs(local_dof);
169  }
170 
171  result.set_basis(tbasis);
172  return result;
173 }
174 
175 //***************************************************************************
176 
191 std::vector<Eigen::MatrixXd> generate_invariant_shuffle_modes(
192  const std::vector<xtal::SymOp> &factor_group,
193  const std::vector<Eigen::PermutationMatrix<Eigen::Dynamic, Eigen::Dynamic,
194  Index>> &permute_group) {
195  if (factor_group.size() != permute_group.size()) {
196  throw std::runtime_error(
197  "error, the size of the symmetry operations in "
198  "generate_invariant_shuffle_modes do not match");
199  }
200  int struc_basis_size = permute_group[0].indices().size();
201  // Generate a basis consisting of individual shuffles of each atom in the
202  // structure.
203  std::vector<Eigen::MatrixXd> displacement_basis;
204  for (int basis_idx = 0; basis_idx < struc_basis_size; ++basis_idx) {
205  for (int dir_idx = 0; dir_idx < 3; ++dir_idx) {
206  Eigen::MatrixXd single_shuffle =
207  Eigen::MatrixXd::Zero(3, struc_basis_size);
208  single_shuffle(dir_idx, basis_idx) = 1.0;
209  displacement_basis.push_back(single_shuffle);
210  }
211  }
212  std::vector<Eigen::VectorXd> displacement_aggregate(
213  displacement_basis.size(),
214  Eigen::VectorXd::Zero(displacement_basis[0].cols() *
215  displacement_basis[0].rows()));
216 
217  for (int idx = 0; idx < factor_group.size(); ++idx) {
218  for (int disp_basis_idx = 0; disp_basis_idx < displacement_basis.size();
219  ++disp_basis_idx) {
220  Eigen::MatrixXd transformed_disp = factor_group[idx].matrix *
221  displacement_basis[disp_basis_idx] *
222  permute_group[idx];
223  displacement_aggregate[disp_basis_idx] +=
224  Eigen::VectorXd(Eigen::Map<Eigen::VectorXd>(
225  transformed_disp.data(),
226  transformed_disp.cols() * transformed_disp.rows()));
227  }
228  }
229  Eigen::MatrixXd sym_disp_basis = Eigen::MatrixXd::Zero(
230  displacement_aggregate.size(), displacement_aggregate[0].size());
231  for (int disp_basis_idx = 0; disp_basis_idx < displacement_basis.size();
232  ++disp_basis_idx) {
233  displacement_aggregate[disp_basis_idx] =
234  displacement_aggregate[disp_basis_idx] / double(factor_group.size());
235  sym_disp_basis.row(disp_basis_idx) = displacement_aggregate[disp_basis_idx];
236  }
237 
238  // Perform a SVD of the resulting aggregate matrix to obtain the rank and
239  // space of the symmetry invariant basis vectors
240  sym_disp_basis.transposeInPlace();
241  Eigen::JacobiSVD<Eigen::MatrixXd> svd(
242  sym_disp_basis, Eigen::ComputeThinU | Eigen::ComputeThinV);
243  int matrix_rank = (svd.singularValues().array().abs() >= CASM::TOL).sum();
244  Eigen::MatrixXd sym_preserving_mode_matrix =
245  svd.matrixV()(Eigen::all, Eigen::seq(0, matrix_rank - 1));
246  std::vector<Eigen::MatrixXd> sym_preserving_modes;
247 
248  for (int sym_mode_idx = 0; sym_mode_idx < matrix_rank; ++sym_mode_idx) {
249  Eigen::Map<Eigen::MatrixXd> _tmp_mode(
250  sym_preserving_mode_matrix.col(sym_mode_idx).data(), 3,
251  struc_basis_size);
252  sym_preserving_modes.push_back(_tmp_mode);
253  }
254  return sym_preserving_modes;
255 }
256 
257 //***************************************************************************
258 void _atomize(SimpleStructure &_sstruc,
259  Eigen::Ref<const Eigen::VectorXi> const &_mol_occ,
260  BasicStructure const &_reference) {
261  Index N_atoms(0);
262 
263  Index nb = _reference.basis().size();
264  Index nv = _mol_occ.size() / nb;
265  Index s = 0;
266  for (Index b = 0; b < nb; ++b) {
267  for (Index v = 0; v < nv; ++v, ++s) {
268  N_atoms += _reference.basis()[b].occupant_dof()[_mol_occ[s]].size();
269  }
270  }
271  _sstruc.atom_info.coords.resize(3, N_atoms);
272  _sstruc.atom_info.names.resize(N_atoms);
273 
274  // s indexes site (i.e., molecule), a is index of atom within the entire
275  // structure
276  Index a = 0;
277  s = 0;
278  for (Index b = 0; b < nb; ++b) {
279  for (Index v = 0; v < nv; ++v, ++s) {
280  Molecule const &molref =
281  _reference.basis()[b].occupant_dof()[_mol_occ[s]];
282 
283  // Initialize atom_info.properties for *molecule* attributes
284  for (auto const &property : _sstruc.mol_info.properties) {
285  auto it = _sstruc.atom_info.properties.find(property.first);
286  if (it == _sstruc.atom_info.properties.end()) {
287  Index dim = AnisoValTraits(property.first).dim();
288  _sstruc.atom_info.properties.emplace(
289  property.first, Eigen::MatrixXd::Zero(dim, N_atoms));
290  }
291  }
292 
293  // ma is index of atom within individual molecule
294  for (Index ma = 0; ma < molref.size(); ++ma, ++a) {
295  // Record position of atom
296  _sstruc.atom_info.cart_coord(a) =
297  _sstruc.mol_info.cart_coord(s) + molref.atom(ma).cart();
298  // Record name of atom
299  _sstruc.atom_info.names[a] = molref.atom(ma).name();
300 
301  // Initialize atom_info.properties for *atom* attributes
302  for (auto const &attr : molref.atom(ma).attributes()) {
303  auto it = _sstruc.atom_info.properties.find(attr.first);
304  if (it == _sstruc.atom_info.properties.end()) {
305  it = _sstruc.atom_info.properties
306  .emplace(attr.first,
307  Eigen::MatrixXd::Zero(attr.second.traits().dim(),
308  N_atoms))
309  .first;
310  }
311  // Record attributes of atom
312  it->second.col(a) = attr.second.value();
313  }
314 
315  // Split molecule attributes into atom attributes using appropriate
316  // extensivity rules If an attribute is specified both at the atom and
317  // molecule levels then the two are added
318  for (auto const &property : _sstruc.mol_info.properties) {
319  auto it = _sstruc.atom_info.properties.find(property.first);
320  if (AnisoValTraits(property.first).extensive()) {
321  it->second.col(a) += property.second.col(s) / double(molref.size());
322  } else {
323  it->second.col(a) += property.second.col(s);
324  }
325  }
326  }
327  }
328  }
329 }
330 
331 //***************************************************************************
332 
333 std::vector<std::set<Index>> mol_site_compatibility(
334  SimpleStructure const &sstruc, BasicStructure const &_prim) {
335  std::vector<std::set<Index>> result;
336  result.reserve(sstruc.mol_info.names.size());
337  for (std::string const &sp : sstruc.mol_info.names) {
338  result.push_back({});
339  for (Index b = 0; b < _prim.basis().size(); ++b) {
340  if (_prim.basis()[b].contains(sp)) {
341  result.back().insert(b);
342  }
343  }
344  }
345  return result;
346 }
347 
348 std::vector<std::set<Index>> atom_site_compatibility(
349  SimpleStructure const &sstruc, BasicStructure const &_prim) {
350  std::vector<std::set<Index>> result;
351  result.reserve(sstruc.atom_info.names.size());
352  for (std::string const &sp : sstruc.atom_info.names) {
353  result.push_back({});
354  for (Index b = 0; b < _prim.basis().size(); ++b) {
355  for (Molecule const &mol : _prim.basis()[b].occupant_dof()) {
356  if (mol.contains(sp)) {
357  result.back().insert(b);
358  break;
359  }
360  }
361  }
362  }
363  return result;
364 }
365 } // namespace xtal
366 } // namespace CASM
std::set< std::string > & s
Specifies traits of (possibly) anisotropic crystal properties.
bool extensive() const
Returns true if type is extensive.
Index dim() const
Conventional dimensionality of this type, returns -1 if always variable.
BasicStructure specifies the lattice and atomic basis of a crystal.
std::vector< Site > & set_basis()
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
const Eigen::Matrix3d & lat_column_mat() const
3x3 matrix with lattice vectors as its columne
Definition: Lattice.hh:110
Class representing a Molecule.
Definition: Molecule.hh:93
Representation of a crystal of molecular and/or atomic occupants, and any additional properties....
std::map< std::string, Eigen::MatrixXd > properties
Info & info(SpeciesMode _mode)
Info of specified context (atomic/molecular)
static Molecule make_atom(std::string const &atom_name)
Return an atomic Molecule with specified name.
Definition: Molecule.cc:86
Eigen::Vector3d const & cart() const
Const access of Cartesian position of atom.
Definition: Molecule.hh:43
AtomPosition const & atom(Index i) const
returns i'th atom position
Definition: Molecule.hh:123
Index size() const
Number of atoms contained Molecule.
Definition: Molecule.hh:113
std::string const & name() const
Const access of species name.
Definition: Molecule.hh:40
std::map< std::string, SpeciesAttribute > const & attributes() const
Definition: Molecule.hh:52
SharedPrimFormatter< jsonParser > factor_group()
static SimpleStructure::Info _replicate(SimpleStructure::Info const &_info, Index mult)
SpeciesMode
enum to refer to a particular representation of the occupants (atomic or molecular)
std::vector< UnitCell > make_lattice_points(const Eigen::Matrix3l &transformation_matrix)
std::vector< Index > superstructure_basis_idx(Eigen::Ref< const Eigen::Matrix3i > const &_T, SimpleStructure const &_sstruc)
Constructs a vector containing the basis index of the ith site in the supercell.
SimpleStructure make_simple_structure(BasicStructure const &_struc)
Construct from decorated structure.
std::vector< std::set< Index > > mol_site_compatibility(SimpleStructure const &sstruc, BasicStructure const &_prim)
Determine which sites of a BasicStructure can host each molecule of a SimpleStructure result[i] is se...
void _atomize(SimpleStructure &_sstruc, Eigen::Ref< const Eigen::VectorXi > const &_mol_occ, BasicStructure const &_reference)
use information in _reference to initialize atom_info from mol_info
std::vector< Eigen::MatrixXd > generate_invariant_shuffle_modes(const std::vector< xtal::SymOp > &factor_group, const std::vector< Eigen::PermutationMatrix< Eigen::Dynamic, Eigen::Dynamic, Index >> &permute_group)
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.
std::vector< std::set< Index > > atom_site_compatibility(SimpleStructure const &sstruc, BasicStructure const &_prim)
Determine which sites of a BasicStructure can host each atom of a SimpleStructure result[i] is set of...
BasicStructure make_superstructure(const BasicStructure &tiling_unit, const Eigen::Matrix< IntegralType, 3, 3, Options > &transformation_matrix)
Main CASM namespace.
Definition: APICommand.hh:8
Eigen::MatrixXd MatrixXd
const double TOL
Definition: definitions.hh:30
std::string DoFKey
Definition: DoFDecl.hh:7
Container::value_type sum(const Container &container, typename Container::value_type init_val=0)
Definition: algorithm.hh:131
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
Definition: CASM_math.hh:104
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
Eigen::VectorXd VectorXd
pair_type property
Definition: settings.cc:142
Struct to encode all information about the crystal basis Info may describe the basis in a atomic cont...
Eigen::MatrixXd coords
(3 x names.size()) matrix of coordinates. coords.col(i) is Cartesian coordinate of site 'i'
std::vector< std::string > names
names[i] is name of species that occupies sites 'i'
Coord cart_coord(Index i)
Access coordinate of site 'i'.
Index size() const
Number of sites is defined as names.size()
std::map< std::string, Eigen::MatrixXd > properties
map of [property name, (m x names.size()) matrix] for all numerical site properties properties are as...
void resize(Index N)
Resize to hold N sites. All coordinates set to zero, all occupants set to "Va".