CASM  1.1.0
A Clusters Approach to Statistical Mechanics
NeighborListInfoInterface.cc
Go to the documentation of this file.
2 
5 #include "casm/casm_io/Log.hh"
12 #include "casm/clex/PrimClex.hh"
13 #include "casm/clex/Supercell.hh"
19 
20 namespace CASM {
21 
22 namespace {
23 
25 struct NeighborListInfoData {
26  NeighborListInfoData(std::shared_ptr<Structure const> _shared_prim,
27  SupercellSymInfo const &_supercell_sym_info,
28  PrimNeighborList const &_prim_neighbor_list,
29  SuperNeighborList const &_supercell_neighbor_list)
30  : shared_prim(_shared_prim),
31  supercell_sym_info(_supercell_sym_info),
32  prim_neighbor_list(_prim_neighbor_list),
33  supercell_neighbor_list(_supercell_neighbor_list) {}
34 
35  std::shared_ptr<Structure const> shared_prim;
36  SupercellSymInfo const &supercell_sym_info;
37  PrimNeighborList const &prim_neighbor_list;
38  SuperNeighborList const &supercell_neighbor_list;
39 };
40 
41 // use for ValueType=bool, int, double, std::string, jsonParser
42 template <typename ValueType>
43 using NeighborListInfoFormatter =
44  GenericDatumFormatter<ValueType, NeighborListInfoData>;
45 
46 NeighborListInfoFormatter<jsonParser> prim_neighbor_list() {
47  return NeighborListInfoFormatter<jsonParser>(
48  "prim_neighbor_list",
49  "Contains an array of unitcells, the ordered set of unitcells the make "
50  "up the neighborhood of the origin unit cell, along with the "
51  "nlist_weight_matrix and nlist_sublat_indices.",
52  [](NeighborListInfoData const &data) -> jsonParser {
53  jsonParser json;
54  std::vector<UnitCell> unitcells{data.prim_neighbor_list.begin(),
55  data.prim_neighbor_list.end()};
56  to_json(unitcells, json["unitcells"], jsonParser::as_flattest());
57  json["weight_matrix"] = data.prim_neighbor_list.weight_matrix();
58  json["sublat_indices"] = data.prim_neighbor_list.sublat_indices();
59  return json;
60  });
61 }
62 
63 NeighborListInfoFormatter<jsonParser> supercell_neighbor_list() {
64  return NeighborListInfoFormatter<jsonParser>(
65  "supercell_neighbor_list",
66  "Contains, for each unitcell in the supercell, "
67  "`linear_unitcell_indices`, the neighborhood of unitcells, and "
68  "`linear_site_indices` the neighborhood of sites. The linear indices can "
69  "be used to lookup coordinates with the `unitcells` and "
70  "`integral_site_coordinates` properties of the supercell.",
71  [](NeighborListInfoData const &data) -> jsonParser {
72  auto const &sym_info = data.supercell_sym_info;
73  auto const &T = sym_info.transformation_matrix_to_super();
74  Index volume = T.determinant();
75  auto const &supercell_lattice = sym_info.supercell_lattice();
76  auto const &L = supercell_lattice.lat_column_mat();
77  auto const &scel_nlist = data.supercell_neighbor_list;
78 
79  jsonParser json;
80  json["transformation_matrix_to_super"] = T;
81  json["supercell_lattice_column_matrix"] = L;
82  json["supercell_lattice_vectors"] = L.transpose();
83  json["supercell_name"] = make_supercell_name(
84  data.shared_prim->point_group(), sym_info.prim_lattice(),
85  sym_info.supercell_lattice());
86  json["supercell_volume"] = volume;
87 
88  json["n_neighbor_sites"] = scel_nlist.sites(0).size();
89  json["n_neighbor_unitcells"] = scel_nlist.unitcells(0).size();
90  json["periodic_images_of_neighborhood_overlap"] = scel_nlist.overlaps();
91 
92  json["linear_site_indices"] = jsonParser::array();
93  json["linear_unitcell_indices"] = jsonParser::array();
94  for (Index l = 0; l < volume; ++l) {
95  json["linear_site_indices"].push_back(scel_nlist.sites(l));
96  json["linear_unitcell_indices"].push_back(scel_nlist.unitcells(l));
97  }
98  return json;
99  });
100 }
101 
102 DataFormatterDictionary<NeighborListInfoData> make_neighbor_list_info_dict() {
103  DataFormatterDictionary<NeighborListInfoData> neighbor_list_info_dict;
104 
105  // properties that require prim and supercell_sym_info
106  neighbor_list_info_dict.insert(prim_neighbor_list(),
108  return neighbor_list_info_dict;
109 }
110 
111 // used with `for_all_orbits` to expand the neighbor list with the orbits
112 // contructed by a ClusterSpecs object
113 struct ExpandPrimNeighborList {
114  ExpandPrimNeighborList(PrimNeighborList &_prim_neighbor_list)
115  : prim_neighbor_list(_prim_neighbor_list) {}
116 
117  template <typename OrbitVecType>
118  void operator()(OrbitVecType const &orbits) const {
119  for (const auto &orbit : orbits) {
120  for (const auto &equiv : orbit) {
121  for (const auto &site : equiv) {
122  prim_neighbor_list.expand(site.unitcell());
123  }
124  }
125  }
126  }
127 
128  PrimNeighborList &prim_neighbor_list;
129 };
130 
131 } // namespace
132 
133 std::string NeighborListInfoInterface::desc() const {
134  std::string description =
135  "Get prim and supercell neighbor list information. The supercell is \n"
136  "specified by the prim and one of the following (else the primitive \n"
137  "cell is used): \n"
138  "- transformation_matrix_to_super \n"
139  "- supercell_lattice_vectors \n"
140  "- supercell_lattice_column_matrix \n"
141  "- supercell_name \n\n";
142 
143  std::string custom_options =
144  " prim: JSON object (optional, default=prim of current project) \n"
145  " See `casm format --prim` for details on the prim format. \n\n"
146 
147  " nlist_weight_matrix: 3x3 array of integer (optional) \n"
148  " The neighbor list weight matrix, W, defines the canonical order\n"
149  " of neighboring UnitCell through lexicographically sorting \n"
150  " [r, i, j, k], where r = (i,j,k).transpose() * W * (i,j,k). If \n"
151  " not provided, it is obtained from 1) the settings of the \n"
152  " current project, or 2) an appropriate default for the prim \n"
153  " lattice so that unit cells are added to the neighborhood in an \n"
154  " approximate sphere around the origin. \n\n"
155 
156  " nlist_sublat_indices: 3x3 array of integer (optional) \n"
157  " The indices of sublattices that should be included in the \n"
158  " supercell neighbor list. If not provided, it is obtained from \n"
159  " 1) the settings of the current project, or 2) indices of the \n"
160  " sites that have >= 2 occupant DoF, or continuous DoF. \n\n"
161 
162  " cluster_specs: array of JSON objects (optional) \n"
163  " The `cluster_specs` array holds one or more JSON descriptions \n"
164  " of cluster orbits, as used in `bspecs.json`. The prim neighbor \n"
165  " is expanded to include the sites in all cluster orbits. \n\n"
166 
167  " basis_set_names: array of string (optional) \n"
168  " Names of basis sets in the current project whose orbits are \n"
169  " all added to the prim neighbor list. \n\n"
170 
171  " unitcells: array of [i,j,k] (optional) \n"
172  " Array of unit cells (specified by [i, j, k] multiples of the \n"
173  " prim lattice vectors) that should be added to the prim neighbor\n"
174  " list. \n\n"
175 
176  " transformation_matrix_to_super: 3x3 array of integer (optional) \n"
177  " Transformation matrix T, defining the supercell lattice vectors\n"
178  " S, in terms of the prim lattice vectors, P: `S = P * T`, where \n"
179  " S and P are column vector matrices. \n\n"
180 
181  " supercell_lattice_vectors: 3x3 array of integer (optional) \n"
182  " Supercell lattice vectors, as a row vector matrix. \n\n"
183 
184  " supercell_lattice_column_matrix: 3x3 array of integer (optional) \n"
185  " Supercell lattice vectors, as a column vector matrix. \n\n"
186 
187  " supercell_name: string (optional) \n"
188  " Unique name given to a supercell, based on the hermite normal \n"
189  " form, of the transformation_matrix_to_super and, if not \n"
190  " canonical, the index of the prim factor group operation that \n"
191  " transforms the canonical supercell into this supercell. \n\n"
192 
193  " properties: array of string (optional, default=[]) \n"
194  " An array of strings specifying which neighbor list properties \n"
195  " to output. The default value of an empty array will print all \n"
196  " properties. The allowed options are: \n\n";
197 
198  std::stringstream ss;
199  auto dict = make_neighbor_list_info_dict();
200  dict.print_help(ss, DatumFormatterClass::Property);
201 
202  return name() + ": \n\n" + description + custom_options + ss.str();
203 }
204 
205 std::string NeighborListInfoInterface::name() const {
206  return "NeighborListInfo";
207 }
208 
211  PrimClex const *primclex) const {
212  Log &log = CASM::log();
213 
214  ParentInputParser parser{json_options};
215  std::runtime_error error_if_invalid{"Error reading NeighborListInfo input"};
216 
217  std::unique_ptr<PrimClex> primclex_ptr;
218  if (primclex == nullptr) {
219  fs::path root = find_casmroot(fs::current_path());
220  if (!root.empty()) {
221  primclex_ptr = notstd::make_unique<PrimClex>(root);
222  primclex = primclex_ptr.get();
223  }
224  }
225 
226  // read "prim"
227  std::shared_ptr<Structure const> shared_prim;
228  if (parser.self.contains("prim")) {
229  // prim provided in input
230  xtal::BasicStructure basic_structure;
231  parser.optional<xtal::BasicStructure>(basic_structure, "prim", TOL);
232  if (parser.valid()) {
233  shared_prim = std::make_shared<Structure const>(basic_structure);
234  }
235  } else if (primclex != nullptr) {
236  // if project provided via api
237  shared_prim = primclex->shared_prim();
238  } else {
239  std::stringstream msg;
240  msg << "Error in NeighborListInfo: No \"prim\" in input and no project "
241  "provided or found.";
242  parser.insert_error("prim", msg.str());
243  }
244  report_and_throw_if_invalid(parser, log, error_if_invalid);
245 
246  // read "nlist_weight_matrix" and "nlist_sublat_indices"
247  Eigen::Matrix3l nlist_weight_matrix;
248  std::set<int> nlist_sublat_indices;
249  if (parser.self.contains("nlist_weight_matrix") ||
250  parser.self.contains("nlist_sublat_indices")) {
251  parser.optional(nlist_weight_matrix, "nlist_weight_matrix");
252  parser.optional(nlist_sublat_indices, "nlist_sublat_indices");
253 
254  } else if (primclex != nullptr) {
255  // if project provided via api
256  try {
257  nlist_weight_matrix = primclex->settings().nlist_weight_matrix();
258  nlist_sublat_indices = primclex->settings().nlist_sublat_indices();
259  } catch (std::exception &e) {
260  parser.error.insert(e.what());
261  }
262  } else {
263  nlist_weight_matrix =
265  nlist_sublat_indices = default_nlist_sublat_indices(*shared_prim);
266  }
267  report_and_throw_if_invalid(parser, log, error_if_invalid);
268 
269  PrimNeighborList prim_neighbor_list{nlist_weight_matrix,
270  nlist_sublat_indices.begin(),
271  nlist_sublat_indices.end()};
272  ExpandPrimNeighborList neighbor_list_expander{prim_neighbor_list};
273 
274  // read "cluster_specs" (optional)
275  if (parser.self.contains("cluster_specs")) {
276  std::vector<jsonParser> cluster_specs_json_vec;
277  parser.optional(cluster_specs_json_vec, "cluster_specs");
278 
279  for (jsonParser const &cluster_specs_json : cluster_specs_json_vec) {
280  InputParser<ClusterSpecs> parser{cluster_specs_json, shared_prim};
281  if (!parser.valid()) {
282  continue;
283  }
284  for_all_orbits(*parser.value, err_log(), neighbor_list_expander);
285  }
286  }
287 
288  // read "basis_set_names" (optional)
289  if (primclex != nullptr && parser.self.contains("basis_set_names")) {
290  std::vector<std::string> basis_set_names;
291  parser.optional(basis_set_names, "basis_set_names");
292  for (auto basis_set_name : basis_set_names) {
293  if (!primclex->has_basis_set_specs(basis_set_name)) {
294  std::stringstream msg;
295  msg << "No basis set named: " << basis_set_name;
296  parser.insert_error("basis_set_names", msg.str());
297  }
298 
299  ClexBasisSpecs const &basis_set_specs =
300  primclex->basis_set_specs(basis_set_name);
301  for_all_orbits(*basis_set_specs.cluster_specs, err_log(),
302  neighbor_list_expander);
303  }
304  }
305 
306  // read "unitcells" (optional)
307  if (parser.self.contains("unitcells")) {
308  std::vector<UnitCell> unitcells;
309  parser.optional(unitcells, "unitcells");
310  prim_neighbor_list.expand(unitcells.begin(), unitcells.end());
311  }
312 
313  // read "transformation_matrix_to_super"
314  Eigen::Matrix3l T;
315  if (parser.self.contains("transformation_matrix_to_super")) {
316  parser.optional(T, "transformation_matrix_to_super");
317 
318  // or read "supercell_lattice_vectors"
319  } else if (parser.self.contains("supercell_lattice_vectors")) {
320  Eigen::Matrix3d L_transpose;
321  parser.optional(L_transpose, "supercell_lattice_vectors");
322  Lattice super_lattice{L_transpose.transpose()};
324  super_lattice, TOL);
325 
326  // or read "supercell_lattice_column_matrix"
327  } else if (parser.self.contains("supercell_lattice_column_matrix")) {
328  Eigen::Matrix3d L;
329  parser.optional(L, "supercell_lattice_column_matrix");
330  Lattice super_lattice{L};
332  super_lattice, TOL);
333 
334  // or read "supercell_name"
335  } else if (parser.self.contains("supercell_name")) {
336  std::string supercell_name;
337  parser.optional(supercell_name, "supercell_name");
339  shared_prim->factor_group(), shared_prim->lattice(), supercell_name);
340  T = superlattice.transformation_matrix_to_super();
341 
342  // else use Identity (prim cell)
343  } else {
345  }
346 
347  // read "properties"
348  std::vector<std::string> properties;
349  parser.optional(properties, "properties");
350  report_and_throw_if_invalid(parser, log, error_if_invalid);
351 
356 
357  auto dict = make_neighbor_list_info_dict();
358  // output all properties if empty
359  if (properties.empty()) {
360  for (auto it = dict.begin(); it != dict.end(); ++it) {
361  if (it->type() == DatumFormatterClass::Property) {
362  properties.push_back(it->name());
363  }
364  }
365  }
366 
367  // format
368  auto formatter = dict.parse(properties);
369  jsonParser json;
370  NeighborListInfoData data{shared_prim, supercell_sym_info, prim_neighbor_list,
372  formatter.to_json(data, json);
373  log << json << std::endl;
374 }
375 
376 } // namespace CASM
SupercellSymInfo const & supercell_sym_info
SuperNeighborList const & supercell_neighbor_list
std::shared_ptr< Structure const > shared_prim
PrimNeighborList const & prim_neighbor_list
Definition: Log.hh:48
std::string name() const override
Enumeration method name (i.e. "prim", "supercell", "dof_space", etc.)
void run(jsonParser const &json_options, PrimClex const *primclex=nullptr) const override
Run NeighborListInfo info method.
PrimClex is the top-level data structure for a CASM project.
Definition: PrimClex.hh:55
The PrimNeighborList gives the coordinates of UnitCell that are neighbors of the origin UnitCell.
Definition: NeighborList.hh:39
A class that collects all symmetry information for for performing symmetry transformations on the sit...
static jsonParser array()
Returns an empty json array.
Definition: jsonParser.hh:409
BasicStructure specifies the lattice and atomic basis of a crystal.
const Eigen::Matrix3l & transformation_matrix_to_super() const
Definition: Superlattice.hh:24
Lattice make_superlattice(const Lattice &lat, const Eigen::Matrix< IntegralType, 3, 3, Options > &transf_mat)
Returns a super Lattice. Transformation matrix must be integer.
Definition: Lattice.hh:287
xtal::Superlattice make_superlattice_from_supercell_name(Structure const &prim, std::string supercell_name)
Construct a Superlattice from the supercell name.
Definition: Supercell.cc:350
std::string make_supercell_name(Structure const &prim, xtal::Superlattice const &superlattice)
Make the supercell name from a Superlattice.
Definition: Supercell.cc:336
ConfigIO::GenericConfigFormatter< jsonParser > properties()
Definition: ConfigIO.cc:785
GenericScelFormatter< double > volume()
Definition: SupercellIO.cc:258
VectorXdSupercellSymInfoFormatter supercell_lattice()
SupercellSymInfoFormatter< jsonParser > unitcells()
IdentitySymRepBuilder Identity()
Eigen::Matrix3l make_transformation_matrix_to_super(const Lattice &tiling_unit, const Lattice &superlattice, double tol)
Definition: Lattice.cc:848
Main CASM namespace.
Definition: APICommand.hh:8
void for_all_orbits(ClusterSpecs const &cluster_specs, std::vector< IntegralCluster > const &generating_elements, FunctorType const &f)
jsonParser & to_json(const ClexDescription &desc, jsonParser &json)
std::set< int > default_nlist_sublat_indices(xtal::BasicStructure const &prim)
std::string description(const SymOp &op, const xtal::Lattice &lat, SymInfoOptions opt=SymInfoOptions())
Print SymInfo to string.
Log & log()
Definition: Log.hh:424
Eigen::Matrix3d Matrix3d
Eigen::Matrix3l default_nlist_weight_matrix(xtal::BasicStructure const &prim, double tol)
const double TOL
Definition: definitions.hh:30
fs::path find_casmroot(const fs::path &cwd)
void report_and_throw_if_invalid(KwargsParser const &parser, Log &log, ErrorType error)
SupercellSymInfo make_supercell_sym_info(Structure const &prim, Lattice const &super_lattice)
Definition: Structure.cc:419
INDEX_TYPE Index
For long integer indexing:
Definition: definitions.hh:39
Log & err_log()
Definition: Log.hh:426
Matrix< long int, 3, 3 > Matrix3l
Definition: eigen.hh:12
PrimClex * primclex
Definition: settings.cc:135
Provides parameters for constructing a cluster expansion basis (ClexBasis)
notstd::cloneable_ptr< ClusterSpecs > cluster_specs