irrep 3.1.1__tar.gz → 3.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {irrep-3.1.1 → irrep-3.2.0}/.github/workflows/tests.yml +1 -7
- {irrep-3.1.1 → irrep-3.2.0}/PKG-INFO +1 -1
- {irrep-3.1.1 → irrep-3.2.0}/irrep/__init__.py +1 -1
- {irrep-3.1.1 → irrep-3.2.0}/irrep/_version.py +3 -3
- irrep-3.2.0/irrep/altermagnetic_transformer.py +90 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/bandstructure.py +5 -5
- {irrep-3.1.1 → irrep-3.2.0}/irrep/kpoint_gpaw.py +35 -27
- {irrep-3.1.1 → irrep-3.2.0}/irrep/parsers/espresso.py +2 -4
- {irrep-3.1.1 → irrep-3.2.0}/irrep/parsers/gpaw.py +1 -2
- {irrep-3.1.1 → irrep-3.2.0}/irrep/spacegroup.py +37 -4
- {irrep-3.1.1 → irrep-3.2.0}/irrep/symmetry_operation.py +34 -25
- irrep-3.2.0/irrep/tests/test_altermagnetic.py +26 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_spacegroup.py +49 -3
- {irrep-3.1.1 → irrep-3.2.0}/irrep.egg-info/PKG-INFO +1 -1
- {irrep-3.1.1 → irrep-3.2.0}/irrep.egg-info/SOURCES.txt +2 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep.egg-info/scm_file_list.json +5766 -5764
- irrep-3.2.0/irrep.egg-info/scm_version.json +8 -0
- irrep-3.1.1/irrep.egg-info/scm_version.json +0 -8
- {irrep-3.1.1 → irrep-3.2.0}/.github/workflows/python-publish.yml +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/.gitignore +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/INSTALL +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/LICENSE +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/MANIFEST.in +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/README.md +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/cli.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/data/msg_numbers.data +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/ebrs.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/gvectors.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/kpoint.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/or_solutions_obtainer.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/parsers/__init__.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/parsers/abinit.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/parsers/common.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/parsers/parse_files_bandstructure.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/parsers/vasp.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/parsers/wannier90.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/spacegroup_irreps.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/__init__.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/conftest.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/ref_data/Fe_qe_dmn_TR=False.pkl +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/ref_data/Fe_qe_dmn_TR=False_irred.pkl +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/ref_data/Fe_qe_dmn_TR=True.pkl +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/ref_data/Fe_qe_dmn_TR=True_irred.pkl +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/ref_data/magmom_Fe_qe_dmn.txt +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/ref_data/spacegroup_Te_TR.npz +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/ref_data/spacegroup_Te_TR_product.npz +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/ref_data/spacegroup_Te_noTR.npz +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/ref_data/spacegroup_Te_noTR_product.npz +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/ref_data/symm_matrix_block.npz +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/ref_data/symm_matrix_full.npz +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_abinit_scalar.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_abinit_spinor.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_dmn.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_ebr_decomposition.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_espresso_hdf5.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_espresso_spinor.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_espresso_spinpol.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_gpaw.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_paw.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_refUC.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_symmetry_indicators.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_symsep.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_vasp_scalar.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_vasp_spinor.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_wannier_scalar.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/tests/test_wannier_spinor.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep/utility.py +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep.egg-info/dependency_links.txt +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep.egg-info/entry_points.txt +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep.egg-info/requires.txt +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/irrep.egg-info/top_level.txt +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/pyproject.toml +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/setup.cfg +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi/POSCAR +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi/README.md +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi/WAVECAR +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi/images/bands.png +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi/images/checktopomat.png +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi/inputs_maxK/INCAR +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi/inputs_maxK/KPOINTS +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi/inputs_maxK/POSCAR +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi/inputs_maxK/POTCAR +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi/inputs_scf/INCAR +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi/inputs_scf/KPOINTS +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi/inputs_scf/POSCAR +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi/inputs_scf/POTCAR +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/README.md +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/images/bands.png +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/images/checktopomat.png +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/inputs/Bi.txt +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/inputs/Se.txt +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/inputs/bands.in +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/inputs/nscf_IrRep.in +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/inputs/pp.bands.in +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/inputs/scf.in +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/out/Bi2Se3.save/charge-density.dat +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/out/Bi2Se3.save/data-file-schema.xml +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/out/Bi2Se3.save/paw.txt +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/out/Bi2Se3.save/wfc1.dat +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/out/Bi2Se3.save/wfc2.dat +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/out/Bi2Se3.save/wfc3.dat +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/out/Bi2Se3.save/wfc4.dat +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/Bi2Se3/out/Bi2Se3.xml +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/SnTe/README.md +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/SnTe/images/bands.png +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/SnTe/images/checktopomat.png +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/SnTe/images/refUC.png +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/SnTe/inputs/Sn.xml +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/SnTe/inputs/Te.xml +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/SnTe/inputs/parameters.in +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/tutorial/SnTe/maxK_WFK +0 -0
- {irrep-3.1.1 → irrep-3.2.0}/uploadpypi.sh +0 -0
|
@@ -37,12 +37,6 @@ jobs:
|
|
|
37
37
|
- name: Install irrep and dependencies
|
|
38
38
|
run: |
|
|
39
39
|
pip install -e .
|
|
40
|
-
- name: Set PYTHONPATH
|
|
41
|
-
run: echo "PYTHONPATH=$(pwd):$(pwd)/irreptables" >> $GITHUB_ENV
|
|
42
|
-
- name: Run tests
|
|
43
|
-
run: pytest
|
|
44
|
-
env:
|
|
45
|
-
PYTHONPATH: ${{ env.PYTHONPATH }}
|
|
46
40
|
- name: pytest
|
|
47
41
|
run: |
|
|
48
|
-
pytest
|
|
42
|
+
pytest
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: irrep
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: A tool to get symmetry proberties of ab-initio wavefunctions, irreduible representations and more.
|
|
5
5
|
Author-email: "Stepan S. Tsirkin" <stepan.tsirkin@ehu.eus>
|
|
6
6
|
License: GNU General Public License v3 (GPLv3)
|
|
@@ -2,4 +2,4 @@ try:
|
|
|
2
2
|
from ._version import version as __version__
|
|
3
3
|
except ImportError:
|
|
4
4
|
__version__ = "unknown"
|
|
5
|
-
from .parsers.parse_files_bandstructure import parse_files as parse_bandstructure
|
|
5
|
+
from .parsers.parse_files_bandstructure import parse_files as parse_bandstructure # noqa: F401
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '3.
|
|
22
|
-
__version_tuple__ = version_tuple = (3,
|
|
21
|
+
__version__ = version = '3.2.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (3, 2, 0)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g5a82e29d3'
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
|
|
3
|
+
from .spacegroup import SpaceGroup
|
|
4
|
+
from .utility import all_close_mod1
|
|
5
|
+
from .symmetry_operation import SymmetryOperation, get_atom_map
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AltermagneticTransformer:
|
|
9
|
+
|
|
10
|
+
def __init__(self, calculator,
|
|
11
|
+
symmetrizer_up,
|
|
12
|
+
alter_symop=None,
|
|
13
|
+
rotation_latt=None,
|
|
14
|
+
translation_latt=None,
|
|
15
|
+
):
|
|
16
|
+
spacegroup_up = symmetrizer_up.spacegroup
|
|
17
|
+
if alter_symop is None:
|
|
18
|
+
alter_symop = SymmetryOperation(rot=rotation_latt,
|
|
19
|
+
trans=translation_latt,
|
|
20
|
+
Lattice=spacegroup_up.Lattice,
|
|
21
|
+
spinor=False
|
|
22
|
+
)
|
|
23
|
+
self.alter_symop = alter_symop
|
|
24
|
+
self.alter_symop.set_gpaw(calculator)
|
|
25
|
+
# self.symops = [symop * alter_symop for symop in spacegroup_up.symmetries]
|
|
26
|
+
self.alter_map = [] # alter_map[i] = j means ki = alter_map_symops[i] * kj
|
|
27
|
+
self.alter_map_isym = []
|
|
28
|
+
self.symmetry_operations = []
|
|
29
|
+
self.k_intermediate = []
|
|
30
|
+
for kirr in symmetrizer_up.kptirr:
|
|
31
|
+
kpt_red = symmetrizer_up.kpoints_all[kirr]
|
|
32
|
+
kpt_red_before_transform = alter_symop.transform_k(kpt_red, inverse=True)
|
|
33
|
+
for ik, kpt in enumerate(symmetrizer_up.kpoints_all):
|
|
34
|
+
if all_close_mod1(kpt, kpt_red_before_transform):
|
|
35
|
+
self.alter_map.append(symmetrizer_up.kpt2kptirr[ik])
|
|
36
|
+
isym = symmetrizer_up.kpt2kptirr_sym[ik]
|
|
37
|
+
self.alter_map_isym.append(isym)
|
|
38
|
+
self.symmetry_operations.append(symmetrizer_up.spacegroup.symmetries[isym])
|
|
39
|
+
self.k_intermediate.append(kpt)
|
|
40
|
+
break
|
|
41
|
+
else:
|
|
42
|
+
raise RuntimeError(f"No corresponding k-point found for R({kpt_red})={kpt_red_before_transform} out of \n{symmetrizer_up.kpoints_all} under the altermagnetic symmetry operation.")
|
|
43
|
+
|
|
44
|
+
@classmethod
|
|
45
|
+
def from_gpaw(cls, calculator, symmetrizer_up, nskip_symmetries=0):
|
|
46
|
+
symop = find_altermagnetic_symmetry(lattice=calculator.atoms.cell,
|
|
47
|
+
positions=calculator.atoms.get_scaled_positions(),
|
|
48
|
+
typat=calculator.atoms.get_atomic_numbers(),
|
|
49
|
+
magmom=calculator.get_magnetic_moments(),
|
|
50
|
+
nskip=nskip_symmetries)
|
|
51
|
+
return cls(calculator, symmetrizer_up, rotation_latt=symop.rotation, translation_latt=symop.translation)
|
|
52
|
+
|
|
53
|
+
def get_kpoint_down(self, ikirr, kpoints_up):
|
|
54
|
+
ik_origin = self.alter_map[ikirr]
|
|
55
|
+
KPtransformed = kpoints_up[ik_origin].get_transformed_copy(
|
|
56
|
+
symmetry_operation=self.symmetry_operations[ikirr],
|
|
57
|
+
k_new=self.k_intermediate[ikirr])
|
|
58
|
+
KPtransformed = KPtransformed.get_transformed_copy(
|
|
59
|
+
symmetry_operation=self.alter_symop,
|
|
60
|
+
k_new=kpoints_up[ikirr].k)
|
|
61
|
+
# TODO : unify the transformations, using just their product
|
|
62
|
+
return KPtransformed
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def find_altermagnetic_symmetry(lattice, positions, typat, magmom, nskip=0):
|
|
66
|
+
magmom = np.array(magmom)
|
|
67
|
+
assert magmom.ndim == 1, "Magnetic moments must be a 1D array."
|
|
68
|
+
positions = np.array(positions)
|
|
69
|
+
assert positions.ndim == 2 and positions.shape[1] == 3, "Positions must be a 2D array with shape (N, 3)."
|
|
70
|
+
typat = np.array(typat)
|
|
71
|
+
assert typat.ndim == 1, "Atom types must be a 1D array."
|
|
72
|
+
assert len(positions) == len(typat)
|
|
73
|
+
assert len(positions) == len(magmom), "Number of positions, atom types, and magnetic moments must match."
|
|
74
|
+
|
|
75
|
+
spacegroup_nomag = SpaceGroup.from_cell(real_lattice=lattice, positions=positions, typat=typat, include_TR=False)
|
|
76
|
+
if nskip >= len(spacegroup_nomag.symmetries) // 2:
|
|
77
|
+
raise ValueError(f"nskip={nskip} is too large for the number of symmetries={len(spacegroup_nomag.symmetries)}.")
|
|
78
|
+
cnt = 0
|
|
79
|
+
for symop in spacegroup_nomag.symmetries:
|
|
80
|
+
atommap, T = get_atom_map(symop, positions)
|
|
81
|
+
# print (f"Checking symmetry operation: {symop}, {atommap=}, {T=}")
|
|
82
|
+
assert np.all(typat[atommap] == typat), "Atom types must match under symmetry operation."
|
|
83
|
+
magmom_transformed = magmom[atommap]
|
|
84
|
+
print(f"{magmom_transformed=}, {atommap=},")
|
|
85
|
+
if np.allclose(magmom_transformed, -magmom):
|
|
86
|
+
cnt += 1
|
|
87
|
+
if cnt > nskip:
|
|
88
|
+
return symop
|
|
89
|
+
else:
|
|
90
|
+
raise ValueError("No altermagnetic symmetry operation found for the given magnetic moments.")
|
|
@@ -544,7 +544,7 @@ class BandStructure:
|
|
|
544
544
|
if read_paw:
|
|
545
545
|
spacegroup.set_gpaw(calculator=parser.calculator)
|
|
546
546
|
from irrep.kpoint_gpaw import OverlapPAW
|
|
547
|
-
overlap_paw = OverlapPAW(
|
|
547
|
+
overlap_paw = OverlapPAW(calc=parser.calculator)
|
|
548
548
|
|
|
549
549
|
NBin, kpred, Lattice, _spinor, typat, positions, EF_in = parser.parse_header()
|
|
550
550
|
if Ecut is None:
|
|
@@ -683,11 +683,9 @@ class BandStructure:
|
|
|
683
683
|
return False
|
|
684
684
|
|
|
685
685
|
kpt_coords = [parser.get_kpt_coord(ik) for ik in kplist]
|
|
686
|
-
log_message(f'Input files contain {NK} k-points:\n {kpt_coords}', verbosity, 1)
|
|
687
686
|
kplist_noskip = [ik for ik in kplist if not check_skip(parser.get_kpt_coord(ik))]
|
|
688
687
|
|
|
689
688
|
|
|
690
|
-
|
|
691
689
|
# Set Fermi energy
|
|
692
690
|
if isinstance(EF, str) and EF.lower() == "auto" or EF is None:
|
|
693
691
|
if EF_in is None:
|
|
@@ -724,8 +722,10 @@ class BandStructure:
|
|
|
724
722
|
|
|
725
723
|
|
|
726
724
|
# To do: create writer of description for this class
|
|
727
|
-
log_message(
|
|
728
|
-
|
|
725
|
+
log_message(f"Wave function file contains total {NK} k-points and {NBin} bands.", verbosity, 1)
|
|
726
|
+
log_message(f"Saving {len(kpt_coords)} k-points and {NBout} bands in the output.", verbosity, 1)
|
|
727
|
+
log_message(f'Saving k-points with coordinates: \n {kpt_coords}', verbosity, 2)
|
|
728
|
+
log_message(f'Saving bands with band indices: {IBstart + 1} to {IBend + 1}', verbosity, 2)
|
|
729
729
|
log_message(f"Energy cutoff in WAVECAR : {Ecut0}", verbosity, 1)
|
|
730
730
|
log_message(f"Energy cutoff reduced to : {Ecut}", verbosity, 1)
|
|
731
731
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
from gpaw.utilities.partition import AtomPartition
|
|
2
1
|
import numpy as np
|
|
3
2
|
from .kpoint import KpointAbstract
|
|
4
3
|
from .utility import cached_einsum
|
|
@@ -24,11 +23,10 @@ class KpointGPAW(KpointAbstract):
|
|
|
24
23
|
def __init__(self, kpt, wavefunction=None, proj=None, nbands=None,
|
|
25
24
|
RecLattice=None,
|
|
26
25
|
atom_positions=None):
|
|
27
|
-
super().__init__(kpt=kpt, num_bands=nbands)
|
|
26
|
+
super().__init__(kpt=kpt, num_bands=nbands, RecLattice=RecLattice)
|
|
28
27
|
self.wavefunction = wavefunction
|
|
29
28
|
self.proj = proj
|
|
30
29
|
self.nbands = nbands
|
|
31
|
-
self.RecLattice = RecLattice
|
|
32
30
|
self.atom_positions = atom_positions
|
|
33
31
|
|
|
34
32
|
@classmethod
|
|
@@ -39,8 +37,8 @@ class KpointGPAW(KpointAbstract):
|
|
|
39
37
|
kpt = calc.wfs.kpt_qs[ibz_index][ispin]
|
|
40
38
|
k = calc.get_ibz_k_points()[ibz_index]
|
|
41
39
|
nbands = IBend - IBstart
|
|
42
|
-
proj =
|
|
43
|
-
|
|
40
|
+
proj = np.hstack([kpt.P_ani[a][IBstart:IBend] for a in range(len(calc.wfs.setups))])
|
|
41
|
+
|
|
44
42
|
# Get projections in ibz
|
|
45
43
|
if RecLattice is None:
|
|
46
44
|
RecLattice = calc.wfs.gd.reciprocal_lattice
|
|
@@ -48,7 +46,10 @@ class KpointGPAW(KpointAbstract):
|
|
|
48
46
|
|
|
49
47
|
wavefunction = np.array([calc.wfs.get_wave_function_array(n, ibz_index, ispin, periodic=True)
|
|
50
48
|
for n in range(IBstart, IBend)])
|
|
51
|
-
return KpointGPAW(kpt=k, wavefunction=wavefunction, proj=proj, nbands=nbands,
|
|
49
|
+
return KpointGPAW(kpt=k, wavefunction=wavefunction, proj=proj, nbands=nbands,
|
|
50
|
+
RecLattice=RecLattice,
|
|
51
|
+
atom_positions=atom_positions)
|
|
52
|
+
|
|
52
53
|
|
|
53
54
|
|
|
54
55
|
def get_transformed_copy(self, symmetry_operation, k_new):
|
|
@@ -69,15 +70,27 @@ class KpointGPAW(KpointAbstract):
|
|
|
69
70
|
|
|
70
71
|
class OverlapPAW:
|
|
71
72
|
|
|
72
|
-
def __init__(self,
|
|
73
|
+
def __init__(self, calc, get_soc=True):
|
|
74
|
+
|
|
73
75
|
self.dO_aii = {}
|
|
74
|
-
for a in wfs.
|
|
75
|
-
self.dO_aii[a] = np.copy(
|
|
76
|
-
self.
|
|
76
|
+
for a, setup in enumerate(calc.wfs.setups):
|
|
77
|
+
self.dO_aii[a] = np.copy(setup.dO_ii)
|
|
78
|
+
self.orb_atom_indices = np.cumsum([0] + [dO.shape[0] for dO in self.dO_aii.values()])
|
|
79
|
+
self.dv = np.copy(calc.wfs.gd.dv)
|
|
80
|
+
if get_soc:
|
|
81
|
+
from gpaw.spinorbit import soc
|
|
82
|
+
self.dVL_avii = [
|
|
83
|
+
soc(calc.wfs.setups[a], calc.hamiltonian.xc, calc.density.D_asp[a])
|
|
84
|
+
for a in range(len(calc.wfs.setups))]
|
|
85
|
+
|
|
77
86
|
# print ("Initialized PAW overlap with dO_ii for atoms", list(self.dO_aii.keys()))
|
|
78
87
|
# print ("dO_ii shapes", {a: dO.shape for a, dO in self.dO_aii.items()})
|
|
79
88
|
# print ("dv", self.dv)
|
|
80
89
|
|
|
90
|
+
def get_orb_indices_on_atom(self, atom_index):
|
|
91
|
+
"""Get the orbital indices corresponding to a specific atom index."""
|
|
92
|
+
return self.orb_atom_indices[[atom_index, atom_index + 1]]
|
|
93
|
+
|
|
81
94
|
def product(self, KP1, KP2,
|
|
82
95
|
include_paw=True,
|
|
83
96
|
include_pseudo=True,
|
|
@@ -101,23 +114,18 @@ class OverlapPAW:
|
|
|
101
114
|
else:
|
|
102
115
|
phases = np.exp(-2j * np.pi * (positions @ bk))
|
|
103
116
|
for a, dO_ii in self.dO_aii.items():
|
|
104
|
-
|
|
117
|
+
I1, I2 = self.get_orb_indices_on_atom(a)
|
|
118
|
+
prod += (proj1[:, I1:I2].conj() @ dO_ii @ (proj2[:, I1:I2].T)) * phases[a]
|
|
105
119
|
return prod
|
|
106
120
|
|
|
107
121
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
self.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def new_paw_projection(proj,
|
|
119
|
-
**kwargs):
|
|
120
|
-
ap = AtomPartitionSerial(proj.atom_partition)
|
|
121
|
-
new_projection = proj.new(bcomm=None, atom_partition=ap, **kwargs)
|
|
122
|
-
new_projection.atom_partition = ap
|
|
123
|
-
return new_projection
|
|
122
|
+
def soc(self, KP1, KP2):
|
|
123
|
+
from ase.units import Hartree
|
|
124
|
+
dVsoc = np.zeros((3, KP1.nbands, KP2.nbands), dtype=complex)
|
|
125
|
+
for a, dVL_vii in enumerate(self.dVL_avii):
|
|
126
|
+
I1, I2 = self.get_orb_indices_on_atom(a)
|
|
127
|
+
P1_mi = KP1.proj[:, I1:I2].conj()
|
|
128
|
+
P2_mi = KP2.proj[:, I1:I2].T
|
|
129
|
+
for t in range(3):
|
|
130
|
+
dVsoc[t] += P1_mi @ dVL_vii[t] @ P2_mi
|
|
131
|
+
return dVsoc * Hartree
|
|
@@ -28,8 +28,7 @@ class ParserEspresso(ParserCommon):
|
|
|
28
28
|
self.recip_lattice_alat_inv = np.linalg.inv(recip_lattice_alat)
|
|
29
29
|
|
|
30
30
|
def parse_header(self, spin_channel=None):
|
|
31
|
-
Ecut0 = float(self.input.find("basis").find("ecutwfc").text)
|
|
32
|
-
Ecut0 *= Hartree_eV
|
|
31
|
+
Ecut0 = float(self.input.find("basis").find("ecutwfc").text) * Hartree_eV
|
|
33
32
|
NK = len(self.bandstr.findall("ks_energies"))
|
|
34
33
|
|
|
35
34
|
self.spin_channel = spin_channel
|
|
@@ -123,8 +122,7 @@ class ParserEspresso(ParserCommon):
|
|
|
123
122
|
NBin = self.NBin_list[0]
|
|
124
123
|
|
|
125
124
|
if getE:
|
|
126
|
-
Energy = np.array(kptxml.find("eigenvalues").text.split(), dtype=float)[NB_skip: NB_skip + NBin]
|
|
127
|
-
Energy *= Hartree_eV
|
|
125
|
+
Energy = np.array(kptxml.find("eigenvalues").text.split(), dtype=float)[NB_skip: NB_skip + NBin] * Hartree_eV
|
|
128
126
|
else:
|
|
129
127
|
Energy = None
|
|
130
128
|
npw = int(kptxml.find("npw").text)
|
|
@@ -158,11 +158,10 @@ def get_soc_gpaw(calc, ik, flatten=True, theta=0, phi=0):
|
|
|
158
158
|
P2_mi = calc.wfs.kpt_qs[q][0].P_ani[a]
|
|
159
159
|
|
|
160
160
|
h_soc[s1, s2] += np.dot(np.dot(P1_mi.conj(), h_ii), P2_mi.T)
|
|
161
|
-
h_soc[:] *= Hartree
|
|
162
161
|
if flatten:
|
|
163
162
|
h_soc_old = h_soc.copy()
|
|
164
163
|
h_soc = np.zeros((2 * m, 2 * m), complex)
|
|
165
164
|
for s1 in range(2):
|
|
166
165
|
for s2 in range(2):
|
|
167
166
|
h_soc[s1::2, s2::2] = h_soc_old[s1, s2]
|
|
168
|
-
return h_soc
|
|
167
|
+
return h_soc * Hartree
|
|
@@ -30,6 +30,8 @@ import os
|
|
|
30
30
|
|
|
31
31
|
from pyxtal import Group
|
|
32
32
|
from sympy import Matrix, sympify
|
|
33
|
+
from sympy.parsing.sympy_parser import parse_expr, standard_transformations, implicit_multiplication_application
|
|
34
|
+
|
|
33
35
|
|
|
34
36
|
|
|
35
37
|
class SpaceGroup:
|
|
@@ -877,6 +879,7 @@ class SpaceGroup:
|
|
|
877
879
|
mag_symprec=0.05,
|
|
878
880
|
typat=None,
|
|
879
881
|
magmom=None,
|
|
882
|
+
magnetic=True,
|
|
880
883
|
spinor=None,
|
|
881
884
|
verbosity=0,
|
|
882
885
|
**kwargs_cell):
|
|
@@ -908,9 +911,12 @@ class SpaceGroup:
|
|
|
908
911
|
lattice = calculator.atoms.cell
|
|
909
912
|
if typat is None:
|
|
910
913
|
typat = calculator.atoms.get_atomic_numbers()
|
|
911
|
-
if
|
|
912
|
-
magmom
|
|
913
|
-
|
|
914
|
+
if magnetic:
|
|
915
|
+
if magmom is None:
|
|
916
|
+
magmom = calculator.get_magnetic_moments()
|
|
917
|
+
assert magmom.shape == (len(calculator.atoms),)
|
|
918
|
+
else:
|
|
919
|
+
magmom = np.zeros(len(calculator.atoms), dtype=float)
|
|
914
920
|
magmom = group_numbers(magmom, precision=mag_symprec)
|
|
915
921
|
magmom_set = set(magmom)
|
|
916
922
|
if len(magmom_set) > 1:
|
|
@@ -1055,7 +1061,8 @@ class SpaceGroup:
|
|
|
1055
1061
|
for sim_vector in conventional_wyckoffs:
|
|
1056
1062
|
|
|
1057
1063
|
# sim_vector is a string on array shape change to numeric or simbolic
|
|
1058
|
-
|
|
1064
|
+
_TRANSFORMS = standard_transformations + (implicit_multiplication_application,)
|
|
1065
|
+
vector = Matrix([parse_expr(v, transformations=_TRANSFORMS) for v in sim_vector.split(',')])
|
|
1059
1066
|
wyckoff_new_base = inv_transformation_matrix * (vector - origin_shift)
|
|
1060
1067
|
|
|
1061
1068
|
# Change to string again
|
|
@@ -1067,6 +1074,32 @@ class SpaceGroup:
|
|
|
1067
1074
|
return wyckoffs_in_cell_base
|
|
1068
1075
|
|
|
1069
1076
|
|
|
1077
|
+
def get_transformed_group_index(self, symmetry_operation):
|
|
1078
|
+
"""
|
|
1079
|
+
calculates the operations S^-1*g*S for a given symmetry operation S and each symmetry operation g in the group. Returns the index of the transformed operation in the group.
|
|
1080
|
+
Also returns the translation difference between the transformed operation and the corresponding operation in the group.
|
|
1081
|
+
"""
|
|
1082
|
+
transformed_group_index = []
|
|
1083
|
+
translation_difference = []
|
|
1084
|
+
symmetry_operation_inv = symmetry_operation.inverse(mod1=False)
|
|
1085
|
+
for sym in self.symmetries:
|
|
1086
|
+
transformed_sym = symmetry_operation_inv.multiply_keeptransl(sym).multiply_keeptransl(symmetry_operation)
|
|
1087
|
+
sym.show()
|
|
1088
|
+
transformed_sym.show()
|
|
1089
|
+
for i, sym2 in enumerate(self.symmetries):
|
|
1090
|
+
if transformed_sym.equals(sym2, mod1=True) and transformed_sym.time_reversal == sym2.time_reversal:
|
|
1091
|
+
transl_diff = transformed_sym.translation - sym2.translation
|
|
1092
|
+
transl_diff_int = np.round(transl_diff).astype(int)
|
|
1093
|
+
if np.allclose(transl_diff, transl_diff_int):
|
|
1094
|
+
transformed_group_index.append(i)
|
|
1095
|
+
translation_difference.append(transl_diff_int)
|
|
1096
|
+
break
|
|
1097
|
+
else:
|
|
1098
|
+
raise ValueError(f"Transformed symmetry operation {transformed_sym.str()} not found in the group")
|
|
1099
|
+
return np.array(transformed_group_index), np.array(translation_difference).astype(int)
|
|
1100
|
+
|
|
1101
|
+
|
|
1102
|
+
|
|
1070
1103
|
def read_sym_file(fname):
|
|
1071
1104
|
"""
|
|
1072
1105
|
Read symmetry operations from a file.
|
|
@@ -91,7 +91,10 @@ class SymmetryOperation():
|
|
|
91
91
|
positions=None,
|
|
92
92
|
translation_mod1=True, spinor_rotation=None):
|
|
93
93
|
self.ind = ind
|
|
94
|
-
|
|
94
|
+
rot_int = np.array(rot.round(), dtype=int)
|
|
95
|
+
if not np.allclose(rot, rot_int, atol=1e-6):
|
|
96
|
+
raise ValueError(f"Rotation matrix is not integer: {rot}")
|
|
97
|
+
self.rotation = rot_int
|
|
95
98
|
self.positions = positions
|
|
96
99
|
self.time_reversal = bool(time_reversal)
|
|
97
100
|
self.real_lattice = Lattice
|
|
@@ -111,7 +114,7 @@ class SymmetryOperation():
|
|
|
111
114
|
self.spinor_rotation = spinor_rotation
|
|
112
115
|
self.sign = 1 # May be changed later externally
|
|
113
116
|
|
|
114
|
-
def inverse(self):
|
|
117
|
+
def inverse(self, mod1=None):
|
|
115
118
|
"""
|
|
116
119
|
Create the inverse symmetry operation.
|
|
117
120
|
|
|
@@ -120,7 +123,7 @@ class SymmetryOperation():
|
|
|
120
123
|
SymmetryOperation
|
|
121
124
|
A new instance of the symmetry operation representing the inverse.
|
|
122
125
|
"""
|
|
123
|
-
rot_inv =
|
|
126
|
+
rot_inv = self.rotation_inv
|
|
124
127
|
trans_inv = -rot_inv @ self.translation
|
|
125
128
|
spinor_rot_inv = self.spinor_rotation.conj().T
|
|
126
129
|
if self.time_reversal:
|
|
@@ -132,7 +135,7 @@ class SymmetryOperation():
|
|
|
132
135
|
time_reversal=self.time_reversal,
|
|
133
136
|
ind=self.ind,
|
|
134
137
|
spinor=self.spinor,
|
|
135
|
-
translation_mod1=self.translation_mod1,
|
|
138
|
+
translation_mod1=self.translation_mod1 if mod1 is None else mod1,
|
|
136
139
|
spinor_rotation=spinor_rot_inv)
|
|
137
140
|
|
|
138
141
|
def __mul__(self, other):
|
|
@@ -216,6 +219,12 @@ class SymmetryOperation():
|
|
|
216
219
|
return False
|
|
217
220
|
return True
|
|
218
221
|
|
|
222
|
+
@cached_property
|
|
223
|
+
def rotation_inv(self):
|
|
224
|
+
rotinv = np.linalg.inv(self.rotation)
|
|
225
|
+
rotinv_int = np.array(rotinv.round(), dtype=int)
|
|
226
|
+
assert np.allclose(rotinv, rotinv_int, atol=1e-6), f"Inverse Rotation matrix is not integer: {rotinv}"
|
|
227
|
+
return rotinv_int
|
|
219
228
|
|
|
220
229
|
@property
|
|
221
230
|
def lattice(self):
|
|
@@ -458,18 +467,18 @@ class SymmetryOperation():
|
|
|
458
467
|
]
|
|
459
468
|
rotstr = [r + r1 for r, r1 in zip(rotstr, rotstr1)]
|
|
460
469
|
|
|
461
|
-
matrix =
|
|
470
|
+
matrix = self.rotation_inv.T
|
|
462
471
|
if self.time_reversal:
|
|
463
|
-
matrix
|
|
472
|
+
matrix = -matrix
|
|
464
473
|
kstring = "gk = [" + ", ".join(
|
|
465
474
|
[parse_row_transform(r) for r in matrix]
|
|
466
475
|
) + "]"
|
|
467
476
|
|
|
468
477
|
|
|
469
478
|
if write_ref:
|
|
470
|
-
matrix = np.
|
|
479
|
+
matrix = np.linalg.inv(R).T
|
|
471
480
|
if self.time_reversal:
|
|
472
|
-
matrix
|
|
481
|
+
matrix = -matrix
|
|
473
482
|
kstring += " | refUC: gk = [" + ", ".join(
|
|
474
483
|
[parse_row_transform(r) for r in matrix]
|
|
475
484
|
) + "]"
|
|
@@ -655,7 +664,7 @@ class SymmetryOperation():
|
|
|
655
664
|
|
|
656
665
|
return d
|
|
657
666
|
|
|
658
|
-
def transform_r(self, vector, inverse=False):
|
|
667
|
+
def transform_r(self, vector, inverse=False, translation=True):
|
|
659
668
|
"""
|
|
660
669
|
Transform a real-space vector (in lattice coordinates) under the symmetry operation.
|
|
661
670
|
|
|
@@ -670,9 +679,15 @@ class SymmetryOperation():
|
|
|
670
679
|
Transformed vector.
|
|
671
680
|
"""
|
|
672
681
|
if inverse:
|
|
673
|
-
|
|
682
|
+
result = np.array(vector)
|
|
683
|
+
if translation:
|
|
684
|
+
result -= self.translation[..., :]
|
|
685
|
+
return result.dot(self.rotation_inv.T)
|
|
674
686
|
else:
|
|
675
|
-
|
|
687
|
+
result = np.array(vector).dot(self.rotation.T).astype(float)
|
|
688
|
+
if translation:
|
|
689
|
+
result += self.translation[..., :]
|
|
690
|
+
return result
|
|
676
691
|
|
|
677
692
|
|
|
678
693
|
@cached_property
|
|
@@ -702,14 +717,6 @@ class SymmetryOperation():
|
|
|
702
717
|
def det(self):
|
|
703
718
|
return np.linalg.det(self.rotation)
|
|
704
719
|
|
|
705
|
-
|
|
706
|
-
@cached_property
|
|
707
|
-
def rotation_inv(self):
|
|
708
|
-
rotinv = np.linalg.inv(self.rotation)
|
|
709
|
-
rotinv_int = np.array(rotinv.round(), dtype=int)
|
|
710
|
-
assert np.allclose(rotinv, rotinv_int, atol=1e-6), f"Inverse Rotation matrix is not integer: {rotinv}"
|
|
711
|
-
return rotinv_int
|
|
712
|
-
|
|
713
720
|
@cached_property
|
|
714
721
|
def spinor_rotation_TR(self):
|
|
715
722
|
"""
|
|
@@ -862,6 +869,7 @@ class SymmetryOperation():
|
|
|
862
869
|
symmetry = SymmetryGpaw1(self)
|
|
863
870
|
R_aii = AtomRotations(setups.setups, setups.id_a, symmetry).get_R_asii()
|
|
864
871
|
self.R_aii = [R_ii[0] for R_ii in R_aii] # remove unnecessary nesting
|
|
872
|
+
self.orb_atom_indices = np.cumsum([0] + [R.shape[0] for R in self.R_aii])
|
|
865
873
|
|
|
866
874
|
# def get_U_aii_gpaw(self, kpoint):
|
|
867
875
|
# """Phase corrected rotation matrices for the PAW projections."""
|
|
@@ -896,16 +904,17 @@ class SymmetryOperation():
|
|
|
896
904
|
proj_rot : Projections
|
|
897
905
|
the rotated projection coefficients
|
|
898
906
|
"""
|
|
899
|
-
from .kpoint_gpaw import new_paw_projection
|
|
900
|
-
mapped_projections =
|
|
901
|
-
|
|
907
|
+
# from .kpoint_gpaw import new_paw_projection
|
|
908
|
+
mapped_projections = np.zeros_like(projections)
|
|
902
909
|
for a, R_ii in enumerate(self.R_aii):
|
|
903
|
-
|
|
910
|
+
b = self.atom_map[a]
|
|
911
|
+
I1, I2 = self.orb_atom_indices[ [a, a + 1]]
|
|
912
|
+
J1, J2 = self.orb_atom_indices[ [b, b + 1]]
|
|
913
|
+
Pout_ni = (projections[:, I1:I2] @ R_ii.T) # * np.exp(2j * np.pi * k_target @ self.atom_map_T[a])
|
|
904
914
|
if self.time_reversal:
|
|
905
915
|
Pout_ni = np.conj(Pout_ni)
|
|
906
916
|
Pout_ni = Pout_ni * np.exp(2j * np.pi * k_target @ self.atom_map_T[a])
|
|
907
|
-
|
|
908
|
-
mapped_projections.array[..., I1:I2] = Pout_ni
|
|
917
|
+
mapped_projections[:, J1:J2] = Pout_ni
|
|
909
918
|
return mapped_projections
|
|
910
919
|
|
|
911
920
|
def rotate_pseudo_wavefunction(self, psi_n_grid, k_origin, k_target):
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from pytest import approx
|
|
3
|
+
|
|
4
|
+
from irrep.altermagnetic_transformer import find_altermagnetic_symmetry
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def test_find_altermagnetic_symmetry():
|
|
8
|
+
|
|
9
|
+
a = 4.134
|
|
10
|
+
c = 6.652
|
|
11
|
+
lattice = a * np.array([[1, 0, 0], [-1 / 2, np.sqrt(3) / 2, 0], [0, 0, c / a]])
|
|
12
|
+
positions = np.array(
|
|
13
|
+
[
|
|
14
|
+
[0, 0, 0],
|
|
15
|
+
[0, 0, 1 / 2],
|
|
16
|
+
[1 / 3, 2 / 3, 1 / 4],
|
|
17
|
+
[2 / 3, 1 / 3, 3 / 4],
|
|
18
|
+
]
|
|
19
|
+
)
|
|
20
|
+
magmom = np.array([1, -1, 0, 0])
|
|
21
|
+
symop = find_altermagnetic_symmetry(lattice=lattice, positions=positions, typat=[1, 1, 2, 2], magmom=magmom)
|
|
22
|
+
assert symop.angle == approx(np.pi / 3), f"Expected angle=np.pi/3, got {symop.angle}"
|
|
23
|
+
assert symop.axis == approx([0, 0, 1]), f"Expected axis=[0, 0, 1], got {symop.axis}"
|
|
24
|
+
assert symop.translation == approx([0, 0, 0.5]), f"Expected translation=[0, 0, 0.5], got {symop.translation}"
|
|
25
|
+
assert symop.inversion is False, f"Expected inversion=False, got {symop.inversion}"
|
|
26
|
+
assert symop.time_reversal is False, f"Expected timereversal=False, got {symop.timereversal}"
|
|
@@ -5,7 +5,8 @@ from irrep.tests.test_dmn import REF_FILES_PATH, TMP_FILES_PATH
|
|
|
5
5
|
|
|
6
6
|
from .conftest import REF_DATA_PATH, TMP_DATA_PATH
|
|
7
7
|
from irrep.utility import group_numbers
|
|
8
|
-
|
|
8
|
+
import sympy
|
|
9
|
+
from sympy.parsing.sympy_parser import parse_expr, standard_transformations, implicit_multiplication_application
|
|
9
10
|
|
|
10
11
|
a = 4.456
|
|
11
12
|
c = 5.926
|
|
@@ -128,5 +129,50 @@ def test_wyckoff_positions():
|
|
|
128
129
|
return
|
|
129
130
|
|
|
130
131
|
|
|
131
|
-
|
|
132
|
-
|
|
132
|
+
def test_wyckoff_positions_2():
|
|
133
|
+
""" Test for MnTe, which has a spacegroup containing WP of the form (2x,...,...), which can break the sympify parser """
|
|
134
|
+
a = 4.17349018
|
|
135
|
+
|
|
136
|
+
cell = (
|
|
137
|
+
np.array([
|
|
138
|
+
[a, 0, 0],
|
|
139
|
+
[-a / 2, np.sqrt(3) * a / 2, 0],
|
|
140
|
+
[0, 0, 6.75345133],
|
|
141
|
+
]),
|
|
142
|
+
|
|
143
|
+
np.array([
|
|
144
|
+
[0, 0, 0],
|
|
145
|
+
[0, 0, 0.5],
|
|
146
|
+
[1 / 3, 2 / 3, 1 / 4],
|
|
147
|
+
[2 / 3, 1 / 3, 3 / 4],
|
|
148
|
+
]),
|
|
149
|
+
|
|
150
|
+
np.array([25, 25, 52, 52]),
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
MnTe_wyckoffs = SpaceGroup.wyckoff_positions(cell)
|
|
154
|
+
|
|
155
|
+
first_MnTe_wyckoffs = [
|
|
156
|
+
[1 / 3, 2 / 3, 0.75],
|
|
157
|
+
[1 / 3, 2 / 3, 0.25],
|
|
158
|
+
[0, 0, 0.25],
|
|
159
|
+
[0, 0, 0],
|
|
160
|
+
]
|
|
161
|
+
print(MnTe_wyckoffs)
|
|
162
|
+
# Testing the first 4 wp because they are numerical arrays not symbols
|
|
163
|
+
for i, wp in enumerate(MnTe_wyckoffs[-4:]):
|
|
164
|
+
numerical_wp = wp.split(',')
|
|
165
|
+
numerical_wp = [ float(x) for x in numerical_wp]
|
|
166
|
+
assert np.allclose(numerical_wp, first_MnTe_wyckoffs[i])
|
|
167
|
+
# checking correct parsing of the symbolic strings
|
|
168
|
+
assert MnTe_wyckoffs[4].split(',')[1] == '2.0*x'
|
|
169
|
+
return
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def test_implicit_multiplication_parsing():
|
|
173
|
+
"""test lines 1060-1061 of spacegroup.py, which use parse_expr with implicit multiplication"""
|
|
174
|
+
x, y = sympy.symbols('x y')
|
|
175
|
+
_TRANSFORMS = standard_transformations + (implicit_multiplication_application,)
|
|
176
|
+
assert parse_expr('2x', transformations=_TRANSFORMS) == 2 * x
|
|
177
|
+
assert parse_expr('-2x+1', transformations=_TRANSFORMS) == -2 * x + 1
|
|
178
|
+
assert parse_expr('2x-y', transformations=_TRANSFORMS) == 2 * x - y
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: irrep
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.2.0
|
|
4
4
|
Summary: A tool to get symmetry proberties of ab-initio wavefunctions, irreduible representations and more.
|
|
5
5
|
Author-email: "Stepan S. Tsirkin" <stepan.tsirkin@ehu.eus>
|
|
6
6
|
License: GNU General Public License v3 (GPLv3)
|
|
@@ -10,6 +10,7 @@ uploadpypi.sh
|
|
|
10
10
|
.github/workflows/tests.yml
|
|
11
11
|
irrep/__init__.py
|
|
12
12
|
irrep/_version.py
|
|
13
|
+
irrep/altermagnetic_transformer.py
|
|
13
14
|
irrep/bandstructure.py
|
|
14
15
|
irrep/cli.py
|
|
15
16
|
irrep/ebrs.py
|
|
@@ -42,6 +43,7 @@ irrep/tests/__init__.py
|
|
|
42
43
|
irrep/tests/conftest.py
|
|
43
44
|
irrep/tests/test_abinit_scalar.py
|
|
44
45
|
irrep/tests/test_abinit_spinor.py
|
|
46
|
+
irrep/tests/test_altermagnetic.py
|
|
45
47
|
irrep/tests/test_dmn.py
|
|
46
48
|
irrep/tests/test_ebr_decomposition.py
|
|
47
49
|
irrep/tests/test_espresso_hdf5.py
|