15 template<
typename CoordType>
17 if(!fs::exists(filepath)) {
18 std::cout <<
"Error in BasicStructure<CoordType>::BasicStructure<CoordType>(const fs::path &filepath)." << std::endl;
19 std::cout <<
" File does not exist at: " << filepath << std::endl;
22 fs::ifstream infile(filepath);
29 template<
typename CoordType>
31 m_lattice(RHS.lattice()), title(RHS.title), basis(RHS.basis) {
39 template<
typename CoordType>
44 for(
Index i = 0; i < basis.size(); i++) {
45 basis[i].set_lattice(lattice(),
CART);
54 template<
typename CoordType>
71 template<
typename CoordType>
75 for(
Index nb = 0; nb < basis.size(); nb++) {
76 basis[nb].set_basis_ind(nb);
85 template<
typename CoordType>
92 template<
typename CoordType>
94 for(
Index i = 0; i < basis.size(); i++) {
102 template<
typename CoordType>
108 Index pg, b0, b1, b2;
114 lattice().generate_point_group(point_group, map_tol);
116 if(factor_group.
size() != 0) {
117 std::cerr <<
"WARNING in BasicStructure<CoordType>::generate_factor_group_slow" << std::endl;
118 std::cerr <<
"The factor group passed isn't empty and it's about to be rewritten!" << std::endl;
119 factor_group.
clear();
123 for(pg = 0; pg < point_group.
size(); pg++) {
127 for(b0 = 0; b0 < basis.size(); b0++) {
128 trans_basis.
push_back(point_group[pg]*basis[b0]);
133 for(b0 = 0; b0 < trans_basis.
size(); b0++) {
135 if(!basis[0].compare_type(trans_basis[b0]))
138 t_tau = basis[0] - trans_basis[b0];
144 double max_error = 0.0;
145 for(b1 = 0; b1 < basis.size(); b1++) {
146 for(b2 = 0; b2 < trans_basis.size(); b2++) {
149 if(basis[b1].
compare(trans_basis[b2], t_tau, map_tol)) {
150 tdist = basis[b1].min_dist(
Coordinate(trans_basis[b2]) + t_tau);
151 if(tdist > max_error) {
160 if(b2 == trans_basis.size()) {
167 if(num_suc_maps == basis.size()) {
187 template<
typename CoordType>
191 factor_group.
clear();
195 generate_factor_group_slow(factor_group, map_tol);
209 lattice().generate_point_group(point_group, map_tol);
212 for(
Index i = 0; i < prim_fg.size(); i++) {
217 for(
Index j = 0; j < prim_grid.size(); j++) {
229 template<
typename CoordType>
232 fg_converge(factor_group, small_tol, large_tol, increment);
237 template<
typename CoordType>
245 for(
double i = small_tol; i < large_tol; i += increment) {
247 factor_group.
clear();
248 generate_factor_group(factor_group, i);
259 std::cout << tols[i] <<
"\t" << num_ops[i] <<
"\t" << is_group[i] <<
"\t" << num_enforced_ops[i] <<
"\t name: " << name[i] <<
"\n";
274 template<
typename CoordType>
277 if(factor_group.
size() <= 0 || !basis.size()) {
278 std::cerr <<
"ERROR in BasicStructure::generate_basis_permutation_representation" << std::endl;
279 std::cerr <<
"You have NOT generated the factor group, or something is very wrong with your structure. I'm quitting!" << std::endl;;
286 std::string clr(100,
' ');
288 for(
Index ng = 0; ng < factor_group.
size(); ng++) {
291 std::cout <<
'\r' << clr.c_str() <<
'\r' <<
"Find permute rep for symOp " << ng <<
"/" << factor_group.
size() << std::flush;
301 if(verbose) std::cout <<
'\r' << clr.c_str() <<
'\r' << std::flush;
321 template<
typename CoordType>
325 copy_attributes_from(prim);
335 for(i = 0; i < prim_grid.size(); i++) {
338 basis.push_back(prim.
basis[j] + prim_grid.coord(i,
PRIM));
342 basis.back().set_lattice(lattice(),
CART);
344 basis.back().within();
348 set_site_internals();
364 template<
typename CoordType>
378 template<
typename CoordType>
381 Index b1, b2, b3, num_suc_maps;
383 for(b1 = 1; b1 < basis.size(); b1++) {
384 if(!basis[0].compare_type(basis[b1])) {
388 tshift = basis[0] - basis[b1];
390 for(b2 = 0; b2 < basis.size(); b2++) {
391 for(b3 = 0; b3 < basis.size(); b3++) {
393 if(basis[b3].
compare(basis[b2], tshift, prim_tol)) {
398 if(b3 == basis.size()) {
403 if(num_suc_maps == basis.size()) {
420 template<
typename CoordType>
423 Eigen::Vector3d prim_vec0(lattice()[0]), prim_vec1(lattice()[1]), prim_vec2(lattice()[2]);
425 Index b1, b2, b3, sh, sh1, sh2;
427 double tvol, min_vol;
428 bool prim_flag =
true;
429 double prim_vol_tol = std::abs(0.5 * lattice().vol() /
double(basis.size()));
431 for(b1 = 1; b1 < basis.size(); b1++) {
432 tshift = basis[0] - basis[b1];
436 for(b2 = 0; b2 < basis.size(); b2++) {
437 for(b3 = 0; b3 < basis.size(); b3++) {
438 if(basis[b3].
compare(basis[b2], tshift, prim_tol)) {
443 if(b3 == basis.size()) {
447 if(num_suc_maps == basis.size()) {
464 min_vol = std::abs(lattice().vol());
465 for(sh = 0; sh < shift.
size(); sh++) {
466 for(sh1 = sh + 1; sh1 < shift.
size(); sh1++) {
467 for(sh2 = sh1 + 1; sh2 < shift.
size(); sh2++) {
468 tvol = std::abs(
triple_prod(shift[sh], shift[sh1], shift[sh2]));
469 if(tvol < min_vol && tvol > prim_vol_tol) {
471 prim_vec0 = shift[sh];
472 prim_vec1 = shift[sh1];
473 prim_vec2 = shift[sh2];
481 Lattice new_lat(prim_vec0, prim_vec1, prim_vec2);
493 lattice().is_supercell_of(reduced_new_lat, pgroup, transmat);
496 for(
int i = 0; i < 3; i++) {
497 for(
int j = 0; j < 3; j++) {
498 transmat(i, j) = floor(transmat(i, j) + 0.5);
502 invtransmat = transmat.inverse();
503 reduced_new_lat_mat = lattice().lat_column_mat();
505 Lattice reconstructed_reduced_new_lat(reduced_new_lat_mat * invtransmat);
510 CoordType tsite(new_prim.
lattice());
511 for(
Index nb = 0; nb < basis.size(); nb++) {
514 if(new_prim.
find(tsite, prim_tol) == new_prim.
basis.
size()) {
535 template<
typename CoordType>
541 for(nb = 0; nb < basis.size(); nb++) {
542 basis[nb].set_basis_ind(nb);
549 template<
typename CoordType>
552 int prim_to_scel = -1;
553 CoordType shifted_site(prim.
lattice());
556 if(!lattice().is_supercell_of(prim.
lattice(), point_group)) {
557 std::cout <<
"*******************************************\n"
558 <<
"ERROR in BasicStructure<CoordType>::map_superstruc_to_prim:\n"
559 <<
"The structure \n";
562 std::cout <<
"is not a supercell of the given prim!\n";
565 std::cout <<
"*******************************************\n";
575 for(
Index pg = 0; pg < prim_grid.size(); pg++) {
577 shifted_site = prim.
basis[pb];
579 shifted_site += prim_grid.coord(pg,
PRIM);
580 shifted_site.set_lattice(lattice(),
CART);
581 shifted_site.within();
588 shifted_site.set_basis_ind(-1);
589 prim_to_scel =
find(shifted_site);
591 if(prim_to_scel == basis.size()) {
592 std::cout <<
"*******************************************\n"
593 <<
"ERROR in BasicStructure<CoordType>::map_superstruc_to_prim:\n"
594 <<
"Cannot associate site \n"
595 << shifted_site <<
"\n"
596 <<
"with a site in the supercell basis. \n"
597 <<
"*******************************************\n";
598 std::cout <<
"The basis_ind and asym_ind are "
599 << shifted_site.basis_ind() <<
"\t "
600 << shifted_site.asym_ind() <<
"\n";
605 basis[prim_to_scel].ind_to_prim = pb;
612 template<
typename CoordType>
template<
typename CoordType2>
614 for(
Index i = 0; i < basis.size(); i++) {
615 if(basis[i].
compare(test_site, tol)) {
624 template<
typename CoordType>
template<
typename CoordType2>
626 for(
Index i = 0; i < basis.size(); i++) {
627 if(basis[i].
compare(test_site, shift, tol)) {
645 template<
typename CoordType>
template<
typename CoordType2>
648 CoordType2 tsite = bsite;
650 tsite.set_lattice(lattice(),
CART);
654 b =
find(tsite, tol);
656 if(b == basis.size()) {
657 std::cerr <<
"ERROR in BasicStructure::get_unit_cell_coord" << std::endl
658 <<
"Could not find a matching basis site." << std::endl
659 <<
" Looking for: FRAC: " << tsite.const_frac() <<
"\n"
660 <<
" CART: " << tsite.const_cart() <<
"\n";
670 template<
typename CoordType>
672 if(ucc[0] < 0 || ucc[0] >= basis.size()) {
673 std::cerr <<
"CRITICAL ERROR: In BasicStructure<CoordType>::get_site(), UnitCellCoord " << ucc <<
" is out of bounds!\n"
674 <<
" Cannot index basis, which contains " << basis.size() <<
" objects.\n";
678 Coordinate trans(Eigen::Vector3d(ucc[1], ucc[2], ucc[3]), lattice(),
FRAC);
679 return basis[ucc[0]] + trans;
684 template<
typename CoordType>
689 for(
Index nb = 0; nb < basis.size(); nb++) {
690 basis[nb].set_lattice(lattice(), mode);
703 template<
typename CoordType>
706 set_site_internals();
781 template<
typename CoordType>
791 for(
Index rf = 0; rf < relaxed_factors.
size(); rf++) {
793 for(
Index b = 0; b < basis.size(); b++) {
794 operbasis.
push_back(relaxed_factors[rf]*basis[b]);
795 operbasis.
back().print(std::cout);
796 std::cout << std::endl;
800 for(
Index b = 0; b < basis.size(); b++) {
801 double smallest = 1000000;
802 Coordinate bshift(lattice()), tshift(lattice());
803 for(
Index ob = 0; ob < operbasis.
size(); ob++) {
804 double dist = operbasis[ob].min_dist(basis[b], tshift);
805 if(dist < smallest) {
810 bshift.
cart() *= (1.0 / relaxed_factors.
size());
811 avg_basis[b] += bshift;
830 template<
typename CoordType>
833 generate_factor_group(factor_group, tolerance);
834 symmetrize(factor_group);
849 template<
typename CoordType>
854 std::cout << cshift.
const_frac() << std::endl;
855 std::cout <<
"WARNING: You're shifting in the c direction! This will mess with your vacuum and/or structure!!" << std::endl;
856 std::cout <<
"See BasicStructure<CoordType>::add_vacuum_shift" << std::endl;
859 Eigen::Vector3d vacuum_vec;
860 vacuum_vec = lattice()[0].cross(lattice()[1]);
861 vacuum_vec.normalize();
862 Lattice new_lattice(lattice()[0],
864 lattice()[2] + vacuum_thickness * vacuum_vec + cshift.
cart());
866 new_surface_struc = *
this;
868 new_surface_struc.initialize();
873 template<
typename CoordType>
875 if(&(shift.
home()) != &lattice()) {
876 std::cout <<
"WARNING: The lattice from your shift coordinate does not match the lattice of your structure!" << std::endl;
877 std::cout <<
"See BasicStructure<CoordType>::add_vacuum_shift" << std::endl << std::endl;
880 add_vacuum_shift(new_surface_struc, vacuum_thickness, shift.
cart(),
CART);
885 template<
typename CoordType>
887 Eigen::Vector3d shift(0, 0, 0);
889 add_vacuum_shift(new_surface_struc, vacuum_thickness, shift,
FRAC);
896 template<
typename CoordType>
899 for(
Index i = 0; i < basis.size(); i++) {
911 template<
typename CoordType>
917 bool read_elem =
false;
919 std::stringstream tstrstream;
921 CoordType tsite(lattice());
924 getline(stream, title);
925 if(title.back() ==
'\r')
926 throw std::runtime_error(std::string(
"Structure file is formatted for DOS. Please convert to Unix format. (This can be done with the dos2unix command.)"));
928 m_lattice.read(stream);
930 stream.ignore(100,
'\n');
934 while(ch !=
'\n' && !stream.eof()) {
941 else if(ch ==
' ' || ch ==
'\t') {
945 else if(ch >=
'0' && ch <=
'9') {
949 throw std::runtime_error(std::string(
"Error attempting to read Structure. Error reading atom names."));
953 if(read_elem ==
true) {
954 stream.ignore(10,
'\n');
960 while(ch !=
'\n' && !stream.eof()) {
961 if(ch >=
'0' && ch <=
'9') {
967 else if(ch ==
' ' || ch ==
'\t') {
972 throw std::runtime_error(std::string(
"Error in line 6 of structure input file. Line 6 of structure input file should contain the number of sites."));
981 while(ch ==
' ' || ch ==
'\t') {
985 if(ch ==
'S' || ch ==
's') {
987 stream.ignore(1000,
'\n');
988 while(ch ==
' ' || ch ==
'\t') {
994 if(ch ==
'D' || ch ==
'd') {
997 else if(ch ==
'C' || ch ==
'c') {
1001 throw std::runtime_error(std::string(
"Error in line 7 of structure input file. Line 7 of structure input file should specify Direct, Cartesian, or Selective Dynamics."));
1004 throw std::runtime_error(std::string(
"Error in line 8 of structure input file. Line 8 of structure input file should specify Direct or Cartesian when Selective Dynamics is on."));
1007 stream.ignore(1000,
'\n');
1009 if(basis.size() != 0) {
1010 std::cerr <<
"The structure is going to be overwritten." << std::endl;
1017 basis.reserve(num_sites);
1018 for(i = 0; i < num_sites; i++) {
1021 sum_elem += num_elem[j];
1024 tsite.read(stream, elem_array[j], SD_flag);
1030 basis.reserve(num_sites);
1031 for(i = 0; i < num_sites; i++) {
1032 tsite.read(stream, SD_flag);
1033 if((stream.rdstate() & std::ifstream::failbit) != 0) {
1034 std::cerr <<
"Error reading site " << i + 1 <<
" from structure input file." << std::endl;
1037 basis.push_back(tsite);
1044 std::istringstream tmp_stream(s);
1045 Eigen::Vector3d coord;
1046 tmp_stream >> coord;
1047 if(tmp_stream.good()) {
1048 throw std::runtime_error(std::string(
"ERROR: too many sites listed in structure input file."));
1058 template<
typename CoordType>
1060 stream << basis.size() <<
'\n';
1061 stream << title <<
'\n';
1062 stream.precision(7);
1064 stream.flags(std::ios::showpoint | std::ios::fixed | std::ios::right);
1066 for(
Index i = 0; i < basis.size(); i++) {
1067 stream << std::setw(2) << basis[i].occ_name() <<
" ";
1068 stream << std::setw(12) << basis[i].cart() <<
'\n';
1075 template<
typename CoordType>
1077 const char quote =
'\'';
1078 const char indent[] =
" ";
1088 for(
int i = 0; i < 70; i++) {
1092 stream <<
"# CRYSTAL DATA\n\n";
1094 for(
int i = 0; i < 70; i++) {
1098 stream <<
"data_CASM\n\n\n";
1100 stream.precision(5);
1102 stream.flags(std::ios::showpoint | std::ios::fixed | std::ios::left);
1104 stream << std::setw(40) <<
"_pd_phase_name" << quote << title << quote <<
'\n';
1105 stream << std::setw(40) <<
"_cell_length_a" << lattice().lengths[0] <<
'\n';
1106 stream << std::setw(40) <<
"_cell_length_b" << lattice().lengths[1] <<
'\n';
1107 stream << std::setw(40) <<
"_cell_length_c" << lattice().lengths[2] <<
'\n';
1108 stream << std::setw(40) <<
"_cell_angle_alpha" << lattice().angles[0] <<
'\n';
1109 stream << std::setw(40) <<
"_cell_angle_beta" << lattice().angles[1] <<
'\n';
1110 stream << std::setw(40) <<
"_cell_angle_gamma" << lattice().angles[2] <<
'\n';
1111 stream << std::setw(40) <<
"_symmetry_space_group_name_H-M" << quote <<
"TBD" << quote <<
'\n';
1112 stream << std::setw(40) <<
"_symmetry_Int_Tables_number" <<
"TBD" <<
"\n\n";
1114 stream <<
"loop_\n";
1115 stream <<
"_symmetry_equiv_pos_as_xyz\n";
1121 stream <<
"loop_\n";
1122 stream << indent <<
"_atom_site_label" <<
'\n';
1123 stream << indent <<
"_atom_site_occupancy" <<
'\n';
1124 stream << indent <<
"_atom_site_fract_x" <<
'\n';
1125 stream << indent <<
"_atom_site_fract_y" <<
'\n';
1126 stream << indent <<
"_atom_site_fract_z" <<
'\n';
1127 stream << indent <<
"_atom_site_adp_type" <<
'\n';
1128 stream << indent <<
"_atom_site_B_iso_or_equiv" <<
'\n';
1129 stream << indent <<
"_atom_site_type_symbol" <<
'\n';
1136 template<
typename CoordType>
1139 for(
Index i = 0; i < basis.size(); i++) {
1151 template<
typename CoordType>
1154 for(
Index i = 0; i < basis.size(); i++) {
1164 template<
typename CoordType>
1172 template<
typename CoordType>
1181 template<
typename CoordType>
1186 json[
"title"] = title;
1189 json[
"lattice"] = lattice();
1192 json[
"basis"] = basis;
1200 template<
typename CoordType>
1212 CoordType coordtype(lattice());
1213 for(
int i = 0; i < json[
"basis"].
size(); i++) {
1215 basis.push_back(coordtype);
1228 template<
typename CoordType>
1234 template<
typename CoordType>
void from_json(const jsonParser &json)
void print_cif(std::ostream &stream) const
size_type size() const
Returns array size if *this is a JSON array, object size if *this is a JSON object, 1 otherwise.
virtual void sort()
Sort SymOp in the SymGroup.
void set_site_internals()
Associate each site with its basis index by setting its internal flags (asym_ind -> -1) ...
bool almost_zero(const T &val, double tol=TOL)
If T is not integral, use std::abs(val) < tol;.
void map_superstruc_to_prim(BasicStructure &prim, const SymGroup &point_group)
Figures out which prim basis each superstructure basis corresponds to.
jsonParser & to_json(jsonParser &json) const
void fill_supercell(const BasicStructure &prim, double map_tol=TOL)
fill an empty structure with the basis of its corresponding primitive cell
static SymOp translation(const Eigen::Ref< const vector_type > &_tau)
static method to create operation that describes pure translation
bool contains(const T &test_elem) const
void from_json(ClexDescription &desc, const jsonParser &json)
Coordinate_impl::CartCoordinate cart()
Set Cartesian coordinate vector and update fractional coordinate vector.
Type-safe ID object for communicating and accessing Symmetry representation info. ...
void generate_point_group(SymGroup &point_group, double pg_tol=TOL) const
Populate.
bool compare(const T &A, const T &B, double tol)
Floating point comparison with tol, return A < B.
void push_back(const T &toPush)
jsonParser & to_json(const ClexDescription &desc, jsonParser &json)
void add_vacuum(BasicStructure &new_surface_struc, double vacuum_thickness) const
Adds vacuum layer on top of ab plane.
bool is_primitive(double prim_tol=TOL) const
BasicStructure specifies the lattice and atomic basis of a crystal.
SymBasisPermute describes how a symmetry operation permutes atoms in a basis.
BasicStructure create_superstruc(const Lattice &scel_lat, double map_tol=TOL) const
Shortcut routine to create a supercell structure and fill it with sites.
BasicStructure & operator+=(const Coordinate &shift)
Translates all atoms in cell.
void generate_factor_group_slow(SymGroup &factor_group, double map_tol) const
const Lattice & lattice() const
void symmetrize(const SymGroup &relaxed_factors)
Derived::Scalar triple_prod(const Derived &vec0, const Derived &vec1, const Derived &vec2)
void set_lattice(const Lattice &lattice, COORD_TYPE mode)
void generate_factor_group(SymGroup &factor_group, double map_tol) const
apply a symmetry operation to the current structure (may change lattice vectors and order of basis at...
const Array< Index >::X2 & get_multi_table() const
const vector_type & const_frac() const
user override to force const Access the fractional coordinate vector
static Coordinate origin(const Lattice &_home)
construct a coordinate describing origin of _home lattice
Index find(const CoordType2 &test_site, double tol=TOL) const
SymGroup is a collection of symmetry operations that satisfy the group property The symmetry operatio...
void set_map_error(const double &value)
double min_dist(const Coordinate &neighbor) const
Returns distance (in Angstr) to nearest periodic image of neighbor.
void print_xyz(std::ostream &stream) const
Output other formats.
COORD_MODE specifies the current coordinate mode (Fractional or Cartesian)
SymOp is the Coordinate representation of a symmetry operation it keeps fraction (FRAC) and Cartesian...
BasisSet operator*(const SymOp &LHS, const BasisSet &RHS)
Represents cartesian and fractional coordinates.
double max_error()
This returns the group's max_error.
EigenIndex Index
For long integer indexing:
void add_vacuum_shift(BasicStructure &new_surface_struc, double vacuum_thickness, Eigen::Vector3d shift, COORD_TYPE mode) const
Add vacuum and shift c vector. The vacuum is always added parallel to c, and the shift vector should ...
const Array< std::complex< double > >::X2 & character_table() const
void set_basis(Array< CoordType > basis_in)
Manually set the basis sites.
Array< CoordType > basis
Lattice vectors that specifies periodicity of the crystal.
Index max_possible_vacancies() const
Counts sites that allow vacancies.
Eigen::CwiseUnaryOp< decltype(std::ptr_fun(boost::math::lround< typename Derived::Scalar >)), const Derived > lround(const Eigen::MatrixBase< Derived > &val)
Round Eigen::MatrixXd to Eigen::MatrixXl.
void fg_converge(double small_tol, double large_tol, double increment)
Iterator find(Iterator begin, Iterator end, const T &value, BinaryCompare q)
Equivalent to std::find(begin, end, value), but with custom comparison.
void set(const COORD_TYPE new_mode)
void enforce_group(double tol=TOL, Index max_size=200)
Enforce group property by adding products of operations to the group.
std::string title
User-specified name of this Structure.
BasicStructure & operator-=(const Coordinate &shift)
virtual void read(std::istream &stream)
Print intpolated images in seperate directries.
Index find_no_trans(const SymOp &test_op) const
Check to see if a SymOp is contained in in SymGroup and return its index.
bool is_group(double tol=TOL) const
Check to see if SymGroup satisfies the group property.
void copy_attributes_from(const BasicStructure &RHS)
jsonParser & put_obj()
Puts new empty JSON object.
CoordType get_site(const UnitCellCoord &ucc) const
UnitCellCoord get_unit_cell_coord(const CoordType2 &test_site, double tol=TOL) const
virtual void push_back(const SymOp &new_op)
Coordinate_impl::FracCoordinate frac()
Set the fractional coordinate vector.
Lattice & make_right_handed()
Flip c vector if it's on the wrong side of a-b plane – return (*this)
void set_lattice(const Lattice &new_lat)
SymGroupRep is an alternative representation of a SymGroup for something other than real space...
SymGroupRepID generate_basis_permutation_representation(const MasterSymGroup &factor_group, bool verbose) const
void within()
Translate all basis sites so that they are inside the unit cell.
const std::string & get_name() const
const Lattice & home() const
Access the home lattice of the coordinate.
bool contains(const Container &container, const T &value)
Equivalent to container.end() != std::find(container.begin(), container.end(), value) ...
Lattice niggli(const Lattice &in_lat, double compare_tol, bool keep_handedness=false)
Convert the given lattice into it's niggli reduced form, with the most standard orientation possilbe...
SymGroupRepID add_representation(const SymGroupRep &new_rep) const
Add a new representation by passing a reference. SymGroup will store a copy.
bool is_primitive(const Configuration &_config)
returns true if _config describes primitive cell of the configuration it describes ...
virtual BasicStructure & operator=(const BasicStructure &RHS)
void set_rep(const SymOpRepresentation &base_rep, const SymOpRepresentation &new_rep) const