|
Quantum 3xplorer (Q3)
An AI-native quantum simulation engine
|
Symmetry analysis and IBZ k-point reduction using spglib. More...
#include <symmetry.hpp>
Static Public Member Functions | |
| static std::string | find_spacegroup (const Crystal &crystal, Real symmetry_precision=math::tolerances::default_symmetry_precision) |
| static std::vector< SymmetryOperation > | get_symmetry_operations (const Crystal &crystal, Real symmetry_precision=math::tolerances::default_symmetry_precision) |
| static int | number_of_symmetry_operations (const Crystal &crystal, Real symmetry_precision=math::tolerances::default_symmetry_precision) |
| Get the number of symmetry operations. | |
| static KPointsGrid | reduce_kpoints (const Crystal &crystal, const KPointsGrid &input_grid, Real symmetry_precision=math::tolerances::default_symmetry_precision) |
| static KPointsGrid | reduce_kpoints_internal (const Crystal &crystal, const KPointsGrid &input_grid, bool use_time_reversal=true, Real symmetry_precision=math::tolerances::default_symmetry_precision) |
| static void | symmetrize_matrix (const Crystal &crystal, const std::vector< SymmetryOperation > &symmetry_operations, Matrix3x3 &tensor) |
| static void | symmetrize_vector (const Crystal &crystal, const std::vector< SymmetryOperation > &symmetry_operations, std::vector< Vector3D > &vector_field) |
Symmetry analysis and IBZ k-point reduction using spglib.
Definition at line 66 of file symmetry.hpp.
|
inlinestatic |
Analyze symmetry of a crystal structure. Returns the international spacegroup symbol.
Definition at line 73 of file symmetry.hpp.
References q3::detail::crystal_to_spglib(), q3::log::info(), q3::Crystal::number_of_atoms(), and q3::log::warn().
Referenced by q3::create_kohn_sham_iterator(), and q3::bindings::SCFSolver::solve().
|
inlinestatic |
Get all symmetry operations (rotation matrices and fractional translations). Rotation matrices are in crystal (fractional) coordinates. Fractional translations are in crystal coordinates. Includes atom_map for each operation: atom_map[na] = image of atom na.
Definition at line 484 of file symmetry.hpp.
References q3::detail::crystal_to_spglib(), q3::Crystal::fractional_position(), q3::SymmetryOperation::fractional_translation, q3::Crystal::number_of_atoms(), q3::SymmetryOperation::reciprocal_rotation, q3::SymmetryOperation::rotation, q3::Crystal::site_symmetry_class(), q3::log::warn(), q3::Vector3D::x, q3::Vector3D::y, and q3::Vector3D::z.
Referenced by q3::build_mean_field_record(), q3::PlanewaveChargeDensitySymmetrizer::build_shells(), q3::PlanewavePseudopotentialKohnShamSCFIterator::cached_symmetry_operations(), q3::FFTGridSizer::compute_fft_factors(), reduce_kpoints_internal(), and q3::symmetrize_stress_contributions().
|
inlinestatic |
Get the number of symmetry operations.
Definition at line 105 of file symmetry.hpp.
References q3::detail::crystal_to_spglib(), and q3::Crystal::number_of_atoms().
Referenced by reduce_kpoints(), symmetrize_matrix(), and symmetrize_vector().
|
inlinestatic |
Reduce a uniform k-grid to the irreducible Brillouin zone. Returns a KPointsGrid with reduced k-points and correct weights.
Definition at line 131 of file symmetry.hpp.
References q3::KPointsGrid::add_kpoint(), q3::Point3D::coordinates, q3::detail::crystal_to_spglib(), q3::KPointsGrid::generate(), q3::KPointsGrid::grid_dimensions(), q3::KPointsGrid::grid_shifts(), q3::log::info(), q3::Crystal::number_of_atoms(), number_of_symmetry_operations(), q3::KPointsGrid::pretty_print(), q3::KPointsGrid::set_grid_metadata(), q3::log::warn(), q3::WeightedPoint3D::weight, q3::Vector3D::x, q3::Vector3D::y, q3::Vector3D::z, and q3::math::tolerances::zero_vector_magnitude_threshold.
Referenced by q3::build_global_kpoint_grid_from_input().
|
inlinestatic |
Reduction rule: iterate k-points in order, and for each unvisited k-point, apply all symmetry operations (+ time reversal) to find and mark equivalent k-points with higher indices. The representative for each equivalence class is the lowest-index member. Note this reduces in a single pass with the crystal's own point group; pw.x instead reduces with the Bravais lattice group and restores the k-points the crystal group does not relate in a second pass, so the two are not the same rule even though the inner loop is.
Unlike reduce_kpoints() which delegates to spg_get_ir_reciprocal_mesh(), this method uses Q3's own symmetry operations (from spglib's spg_get_dataset, via get_symmetry_operations()) and performs the equivalence checking internally, ensuring identical IBZ representatives.
Uses the actual (atomic-basis-aware) crystal point group, not the Bravais lattice's holohedral group: for any crystal whose basis reduces the symmetry below the lattice's (e.g. a finite-difference-displaced structure, or any multi-atom basis at a less-than-maximal-symmetry arrangement), the lattice's holohedral rotations include operations that are not actual symmetries of the decorated crystal – treating k-points related only by one of those extra operations as equivalent silently corrupts the k-point sum (see TODOs.md's "IBZ k-point vector reconstruction" writeup). Reuses reciprocal_rotation (= (R^{-1})^T), the same convention already used for G-vector transformation in the density symmetrizer, since k-vectors are reciprocal-space quantities, not real-space positions – crystallographic rotation matrices in a (generally oblique) fractional basis are not self-inverse-transpose.
The crystal's actual (basis-aware) point group – NOT compute_bravais_lattice_rotations(), which only looks at lattice vectors and ignores whether the atomic decoration actually respects each candidate rotation.
The mesh is the one the caller already generated, read rather than rebuilt. Reconstructing it here meant a second construction that had to agree with KPointsGrid::generate() on ordering, on the shift convention and on zone folding, with nothing checking that it did – and the two did not fold identically: this one left coordinates in [0,1) and folded only on the way out, while the grid folds as it generates. Reading the list removes the question.
The numbering is internal either way. It decides only which member of each equivalence class becomes the representative; the spglib path (reduce_kpoints, selected by ibz_reduction_method) numbers the same mesh in the opposite order and travels through the same KPointsGrid, results.json, checkpoint and BerkeleyGW writers.
has_representative[i] records whether k-point i has already been folded onto an earlier one. Asking that question directly, rather than encoding it as "the map points at itself", means reading the bookkeeping never requires knowing the convention first.
k-vectors are reciprocal-space quantities: use reciprocal_rotation (= (R^{-1})^T), not rotation (the real-space/position convention) – crystallographic rotation matrices are not self-inverse-transpose in a generally oblique fractional basis (e.g. FCC's rhombohedral primitive cell).
Already in the first BZ: KPointsGrid::generate() folds to [-0.5, 0.5) as it builds. Folding again here is not a no-op – std::round(-0.5) is -1, so a coordinate sitting exactly on the zone boundary would come back as +0.5 and name the opposite face. The fold belonged to the mesh this function used to rebuild for itself, and it left with it.
Build final KPointsGrid with normalized weights w_k = count_k / total * 2 (factor 2 for spin degeneracy)
Definition at line 262 of file symmetry.hpp.
References q3::KPointsGrid::add_kpoint(), q3::Point3D::coordinates, get_symmetry_operations(), q3::KPointsGrid::grid_dimensions(), q3::KPointsGrid::grid_shifts(), q3::log::info(), q3::KPointsGrid::kpoints(), q3::KPointsGrid::number_of_kpoints(), q3::KPointsGrid::pretty_print(), q3::KPointsGrid::set_grid_metadata(), q3::WeightedPoint3D::weight, q3::Vector3D::x, q3::Vector3D::y, and q3::Vector3D::z.
Referenced by q3::build_global_kpoint_grid_from_input().
|
inlinestatic |
Symmetrize a rank-2 tensor (3×3 matrix) such as the stress tensor. Convert to crystal coordinates, average over the point group, convert back: T'[i][j] = (1/n_ops) Σ_op Σ_{k,l} rotation[k][i] * rotation[l][j] * T[k][l], i.e. the same group-average projector symmetrize_vector applies, with both tensor indices carried instead of one. With no atom index there is no image lookup, and because the sum runs over the whole group it is unchanged by replacing each operation with its inverse.
Definition at line 740 of file symmetry.hpp.
References q3::Crystal::lattice_vectors(), number_of_symmetry_operations(), and q3::Crystal::reciprocal_lattice_vectors().
Referenced by q3::symmetrize_stress_contributions().
|
inlinestatic |
Symmetrize a vector quantity f(3, nat) such as forces. Convert to crystal coordinates, average over the symmetry operations (using the rotation matrices and the atom mapping), convert back to Cartesian. The average is the group-average (Reynolds) projector onto the subspace of fields invariant under the crystal's point group: an already-symmetric field is an exact fixed point, and any component the group forbids is projected to zero.
In crystal coordinates the symmetrized field is result[atom][i] = Σ_op Σ_j rotation[j][i] * work[atom_map[atom]][j] / n_ops, i.e. the stored .rotation TRANSPOSED, applied to the IMAGE atom's components.
Why transposed, and why paired with the image. work holds the covariant components w_i = F · a_i. Since an operation maps the lattice onto itself as M a_i = Σ_j R[j][i] a_j (with R the stored fractional-coordinate rotation for positions, x' = R x), the covariant components of the ROTATED field are (R^{-1})^T w. The symmetry-restoring average is the group average F_sym(a) = (1/n_ops) Σ_op M_op^{-1} F(op(a)), whose covariant form needs the transform of the INVERSE operation – which is R^T – applied to the components at the image atom op(a) = atom_map[atom]. That combination, and only that combination, leaves an already-symmetric field unchanged.
Note R^T is NOT (R^{-1})^T here: an integer crystallographic rotation in a fractional basis is not orthogonal, so the two differ (the same point this class makes for k-vectors in reduce_kpoints_internal). Using reciprocal_rotation = (rotation^{-1})^T with the image atom would not be a fixed point of an already-symmetric field.
Definition at line 634 of file symmetry.hpp.
References q3::Crystal::lattice_vectors(), q3::Crystal::number_of_atoms(), number_of_symmetry_operations(), and q3::Crystal::reciprocal_lattice_vectors().