irrep 3.2.0__tar.gz → 3.4.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.4.0/.github/workflows/tests.yml +46 -0
- {irrep-3.2.0 → irrep-3.4.0}/PKG-INFO +1 -1
- {irrep-3.2.0 → irrep-3.4.0}/irrep/_version.py +3 -3
- {irrep-3.2.0 → irrep-3.4.0}/irrep/altermagnetic_transformer.py +17 -8
- {irrep-3.2.0 → irrep-3.4.0}/irrep/bandstructure.py +22 -5
- {irrep-3.2.0 → irrep-3.4.0}/irrep/kpoint.py +1 -3
- {irrep-3.2.0 → irrep-3.4.0}/irrep/kpoint_gpaw.py +34 -29
- {irrep-3.2.0 → irrep-3.4.0}/irrep/parsers/espresso.py +0 -1
- {irrep-3.2.0 → irrep-3.4.0}/irrep/parsers/gpaw.py +83 -7
- {irrep-3.2.0 → irrep-3.4.0}/irrep/spacegroup.py +43 -65
- irrep-3.4.0/irrep/storage.py +69 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/symmetry_operation.py +43 -27
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/conftest.py +13 -0
- irrep-3.4.0/irrep/tests/test_gpaw.py +125 -0
- irrep-3.4.0/irrep/tests/test_gpaw_vs_legacy.py +46 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_paw.py +39 -13
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_spacegroup.py +21 -1
- {irrep-3.2.0 → irrep-3.4.0}/irrep/utility.py +11 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep.egg-info/PKG-INFO +1 -1
- {irrep-3.2.0 → irrep-3.4.0}/irrep.egg-info/SOURCES.txt +2 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep.egg-info/scm_file_list.json +13 -6
- irrep-3.4.0/irrep.egg-info/scm_version.json +8 -0
- irrep-3.2.0/.github/workflows/tests.yml +0 -42
- irrep-3.2.0/irrep/tests/test_gpaw.py +0 -68
- irrep-3.2.0/irrep.egg-info/scm_version.json +0 -8
- {irrep-3.2.0 → irrep-3.4.0}/.github/workflows/python-publish.yml +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/.gitignore +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/INSTALL +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/LICENSE +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/MANIFEST.in +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/README.md +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/__init__.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/cli.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/data/msg_numbers.data +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/ebrs.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/gvectors.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/or_solutions_obtainer.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/parsers/__init__.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/parsers/abinit.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/parsers/common.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/parsers/parse_files_bandstructure.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/parsers/vasp.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/parsers/wannier90.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/spacegroup_irreps.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/__init__.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/ref_data/Fe_qe_dmn_TR=False.pkl +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/ref_data/Fe_qe_dmn_TR=False_irred.pkl +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/ref_data/Fe_qe_dmn_TR=True.pkl +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/ref_data/Fe_qe_dmn_TR=True_irred.pkl +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/ref_data/magmom_Fe_qe_dmn.txt +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/ref_data/spacegroup_Te_TR.npz +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/ref_data/spacegroup_Te_TR_product.npz +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/ref_data/spacegroup_Te_noTR.npz +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/ref_data/spacegroup_Te_noTR_product.npz +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/ref_data/symm_matrix_block.npz +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/ref_data/symm_matrix_full.npz +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_abinit_scalar.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_abinit_spinor.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_altermagnetic.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_dmn.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_ebr_decomposition.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_espresso_hdf5.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_espresso_spinor.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_espresso_spinpol.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_refUC.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_symmetry_indicators.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_symsep.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_vasp_scalar.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_vasp_spinor.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_wannier_scalar.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep/tests/test_wannier_spinor.py +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep.egg-info/dependency_links.txt +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep.egg-info/entry_points.txt +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep.egg-info/requires.txt +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/irrep.egg-info/top_level.txt +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/pyproject.toml +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/setup.cfg +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi/POSCAR +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi/README.md +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi/WAVECAR +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi/images/bands.png +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi/images/checktopomat.png +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi/inputs_maxK/INCAR +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi/inputs_maxK/KPOINTS +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi/inputs_maxK/POSCAR +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi/inputs_maxK/POTCAR +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi/inputs_scf/INCAR +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi/inputs_scf/KPOINTS +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi/inputs_scf/POSCAR +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi/inputs_scf/POTCAR +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/README.md +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/images/bands.png +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/images/checktopomat.png +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/inputs/Bi.txt +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/inputs/Se.txt +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/inputs/bands.in +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/inputs/nscf_IrRep.in +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/inputs/pp.bands.in +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/inputs/scf.in +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/charge-density.dat +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/data-file-schema.xml +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/paw.txt +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/wfc1.dat +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/wfc2.dat +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/wfc3.dat +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/wfc4.dat +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.xml +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/SnTe/README.md +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/SnTe/images/bands.png +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/SnTe/images/checktopomat.png +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/SnTe/images/refUC.png +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/SnTe/inputs/Sn.xml +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/SnTe/inputs/Te.xml +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/SnTe/inputs/parameters.in +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/tutorial/SnTe/maxK_WFK +0 -0
- {irrep-3.2.0 → irrep-3.4.0}/uploadpypi.sh +0 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches:
|
|
6
|
+
- master
|
|
7
|
+
pull_request:
|
|
8
|
+
branches:
|
|
9
|
+
- master
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
strategy:
|
|
14
|
+
max-parallel: 20
|
|
15
|
+
fail-fast: false
|
|
16
|
+
matrix:
|
|
17
|
+
os: [ubuntu-latest]
|
|
18
|
+
python-version: ["3.13"]
|
|
19
|
+
gpaw-version: ["25.7", "26"]
|
|
20
|
+
|
|
21
|
+
runs-on: ${{ matrix.os }}
|
|
22
|
+
|
|
23
|
+
defaults:
|
|
24
|
+
run:
|
|
25
|
+
shell: bash -el {0} # needed so the conda env is activated in every step
|
|
26
|
+
|
|
27
|
+
steps:
|
|
28
|
+
- uses: actions/checkout@v4
|
|
29
|
+
- name: Set up conda
|
|
30
|
+
uses: conda-incubator/setup-miniconda@v3
|
|
31
|
+
with:
|
|
32
|
+
python-version: ${{ matrix.python-version }}
|
|
33
|
+
channels: conda-forge
|
|
34
|
+
channel-priority: strict
|
|
35
|
+
activate-environment: test
|
|
36
|
+
- name: Install GPAW ${{ matrix.gpaw-version }} from conda-forge
|
|
37
|
+
run: |
|
|
38
|
+
conda install -y "gpaw=${{ matrix.gpaw-version }}" pytest
|
|
39
|
+
python -c "import gpaw; print('GPAW', gpaw.__version__)"
|
|
40
|
+
- name: Install tables from local repo, not from pypi
|
|
41
|
+
working-directory: ./irreptables
|
|
42
|
+
run: pip install -e .
|
|
43
|
+
- name: Install irrep and dependencies
|
|
44
|
+
run: pip install -e .
|
|
45
|
+
- name: pytest
|
|
46
|
+
run: pytest
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: irrep
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.4.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)
|
|
@@ -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.4.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (3, 4, 0)
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'gfe03a819e'
|
|
@@ -42,27 +42,29 @@ class AltermagneticTransformer:
|
|
|
42
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
43
|
|
|
44
44
|
@classmethod
|
|
45
|
-
def from_gpaw(cls, calculator, symmetrizer_up, nskip_symmetries=0):
|
|
45
|
+
def from_gpaw(cls, calculator, symmetrizer_up, nskip_symmetries=0, tol_magmom=1e-4):
|
|
46
46
|
symop = find_altermagnetic_symmetry(lattice=calculator.atoms.cell,
|
|
47
47
|
positions=calculator.atoms.get_scaled_positions(),
|
|
48
48
|
typat=calculator.atoms.get_atomic_numbers(),
|
|
49
49
|
magmom=calculator.get_magnetic_moments(),
|
|
50
|
-
nskip=nskip_symmetries
|
|
50
|
+
nskip=nskip_symmetries,
|
|
51
|
+
tol=tol_magmom)
|
|
51
52
|
return cls(calculator, symmetrizer_up, rotation_latt=symop.rotation, translation_latt=symop.translation)
|
|
52
53
|
|
|
53
54
|
def get_kpoint_down(self, ikirr, kpoints_up):
|
|
54
55
|
ik_origin = self.alter_map[ikirr]
|
|
55
56
|
KPtransformed = kpoints_up[ik_origin].get_transformed_copy(
|
|
56
57
|
symmetry_operation=self.symmetry_operations[ikirr],
|
|
57
|
-
k_new=self.k_intermediate[ikirr])
|
|
58
|
+
k_new=self.k_intermediate[ikirr], store=False)
|
|
58
59
|
KPtransformed = KPtransformed.get_transformed_copy(
|
|
59
60
|
symmetry_operation=self.alter_symop,
|
|
60
|
-
k_new=kpoints_up[ikirr].k)
|
|
61
|
+
k_new=kpoints_up[ikirr].k, store=False)
|
|
61
62
|
# TODO : unify the transformations, using just their product
|
|
62
63
|
return KPtransformed
|
|
63
64
|
|
|
64
65
|
|
|
65
|
-
def find_altermagnetic_symmetry(lattice, positions, typat, magmom, nskip=0
|
|
66
|
+
def find_altermagnetic_symmetry(lattice, positions, typat, magmom, nskip=0,
|
|
67
|
+
all=False, tol=1e-4):
|
|
66
68
|
magmom = np.array(magmom)
|
|
67
69
|
assert magmom.ndim == 1, "Magnetic moments must be a 1D array."
|
|
68
70
|
positions = np.array(positions)
|
|
@@ -76,15 +78,22 @@ def find_altermagnetic_symmetry(lattice, positions, typat, magmom, nskip=0):
|
|
|
76
78
|
if nskip >= len(spacegroup_nomag.symmetries) // 2:
|
|
77
79
|
raise ValueError(f"nskip={nskip} is too large for the number of symmetries={len(spacegroup_nomag.symmetries)}.")
|
|
78
80
|
cnt = 0
|
|
81
|
+
if all:
|
|
82
|
+
symop_list = []
|
|
79
83
|
for symop in spacegroup_nomag.symmetries:
|
|
80
84
|
atommap, T = get_atom_map(symop, positions)
|
|
81
85
|
# print (f"Checking symmetry operation: {symop}, {atommap=}, {T=}")
|
|
82
86
|
assert np.all(typat[atommap] == typat), "Atom types must match under symmetry operation."
|
|
83
87
|
magmom_transformed = magmom[atommap]
|
|
84
|
-
print(f"{magmom_transformed=}, {atommap=},")
|
|
85
|
-
if np.allclose(magmom_transformed, -magmom):
|
|
88
|
+
print(f"{magmom_transformed=}, {atommap=}, m-transformed={magmom_transformed + magmom}")
|
|
89
|
+
if np.allclose(magmom_transformed, -magmom, atol=tol):
|
|
86
90
|
cnt += 1
|
|
87
91
|
if cnt > nskip:
|
|
88
|
-
|
|
92
|
+
if all:
|
|
93
|
+
symop_list.append(symop)
|
|
94
|
+
else:
|
|
95
|
+
return symop
|
|
96
|
+
if all:
|
|
97
|
+
return symop_list
|
|
89
98
|
else:
|
|
90
99
|
raise ValueError("No altermagnetic symmetry operation found for the given magnetic moments.")
|
|
@@ -22,14 +22,14 @@ import functools
|
|
|
22
22
|
import numpy as np
|
|
23
23
|
from functools import cached_property
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
from .parsers.gpaw import check_legacy_gpaw
|
|
26
26
|
from .parsers import ParserAbinit, ParserVasp, ParserEspresso, ParserW90, ParserGPAW
|
|
27
27
|
from .kpoint import Kpoint
|
|
28
28
|
from .spacegroup import SpaceGroup
|
|
29
29
|
from .spacegroup_irreps import SpaceGroupIrreps
|
|
30
30
|
from .gvectors import sortIG, calc_gvectors
|
|
31
31
|
from .utility import get_block_indices, get_mapping_irr, grid_from_kpoints, log_message, UniqueListMod1, restore_full_grid, select_irreducible
|
|
32
|
-
|
|
32
|
+
from .storage import DummyStorage
|
|
33
33
|
try:
|
|
34
34
|
from irreptables.ebrs import load_ebr_data
|
|
35
35
|
except ImportError:
|
|
@@ -181,9 +181,10 @@ class BandStructure:
|
|
|
181
181
|
efermi=0.0,
|
|
182
182
|
Ecut=None,
|
|
183
183
|
kwargs_kpoint=None,
|
|
184
|
+
storage=None,
|
|
184
185
|
**kwargs_parser):
|
|
185
186
|
if len(kwargs_parser) > 0:
|
|
186
|
-
raise ValueError(f"the following kwargs are not recognized by BandStructure-__init__(): {list(kwargs_parser.keys())}, please use BandStructure.from_???() class methods to parse files instead of calling BandStructure.__init__() directly.")
|
|
187
|
+
raise ValueError(f"the following kwargs are not recognized by BandStructure-__init__(): {list(kwargs_parser.keys())}, \n If you meant the old API, please use BandStructure.from_???() class methods to parse files instead of calling BandStructure.__init__() directly.")
|
|
187
188
|
self.kpoints = kpoints
|
|
188
189
|
if kpoints_paw is not None:
|
|
189
190
|
self.kpoints_paw = kpoints_paw
|
|
@@ -193,6 +194,9 @@ class BandStructure:
|
|
|
193
194
|
self.efermi = efermi
|
|
194
195
|
self.Ecut = Ecut
|
|
195
196
|
self.kwargs_kpoint = kwargs_kpoint
|
|
197
|
+
if storage is None:
|
|
198
|
+
storage = DummyStorage()
|
|
199
|
+
self.storage = storage
|
|
196
200
|
self.kpoint_getter = kpoint_getter
|
|
197
201
|
self.kpoint_getter_paw = kpoint_getter_paw
|
|
198
202
|
self.kplist = kplist
|
|
@@ -525,8 +529,12 @@ class BandStructure:
|
|
|
525
529
|
spacegroup=None,
|
|
526
530
|
read_kpoints=True,
|
|
527
531
|
read_paw=False,
|
|
532
|
+
store_paw=True,
|
|
533
|
+
storage="tmp_irrep_storage",
|
|
534
|
+
legacy_gpaw=None,
|
|
528
535
|
**kwargs
|
|
529
536
|
):
|
|
537
|
+
legacy_gpaw = check_legacy_gpaw(legacy_gpaw, calculator_gpaw)
|
|
530
538
|
|
|
531
539
|
if spacegroup is None:
|
|
532
540
|
cls_spacegroup, kwargs_spacegroup = cls.get_spacegroup_cls(spin_channel=spin_channel, irreps=irreps, **kwargs)
|
|
@@ -542,6 +550,13 @@ class BandStructure:
|
|
|
542
550
|
verbosity=verbosity
|
|
543
551
|
)
|
|
544
552
|
if read_paw:
|
|
553
|
+
if isinstance(storage, str):
|
|
554
|
+
if store_paw:
|
|
555
|
+
from .storage import Storage
|
|
556
|
+
storage = Storage(storage)
|
|
557
|
+
else:
|
|
558
|
+
from .storage import DummyStorage
|
|
559
|
+
storage = DummyStorage()
|
|
545
560
|
spacegroup.set_gpaw(calculator=parser.calculator)
|
|
546
561
|
from irrep.kpoint_gpaw import OverlapPAW
|
|
547
562
|
overlap_paw = OverlapPAW(calc=parser.calculator)
|
|
@@ -574,7 +589,8 @@ class BandStructure:
|
|
|
574
589
|
from irrep.kpoint_gpaw import KpointGPAW
|
|
575
590
|
kp_gpaw = KpointGPAW.from_gpaw(calc=calculator_gpaw, ibz_index=ik, ispin=spin_channel,
|
|
576
591
|
RecLattice=spacegroup.reciprocal_lattice,
|
|
577
|
-
IBstart=IBstart, IBend=IBend
|
|
592
|
+
IBstart=IBstart, IBend=IBend,
|
|
593
|
+
storage=storage)
|
|
578
594
|
return kp_gpaw
|
|
579
595
|
else:
|
|
580
596
|
get_kpoint_paw = None
|
|
@@ -582,7 +598,8 @@ class BandStructure:
|
|
|
582
598
|
bandstr = cls(kplist=kplist_noskip, spacegroup=spacegroup, Ecut=Ecut, mp_grid=mp_grid, efermi=efermi,
|
|
583
599
|
overlap_paw=overlap_paw if read_paw else None,
|
|
584
600
|
kpoint_getter_paw=get_kpoint_paw,
|
|
585
|
-
kpoint_getter=get_kpoint
|
|
601
|
+
kpoint_getter=get_kpoint,
|
|
602
|
+
storage=storage)
|
|
586
603
|
if read_kpoints:
|
|
587
604
|
bandstr.read_all_kpoints()
|
|
588
605
|
if read_paw:
|
|
@@ -751,7 +751,7 @@ class Kpoint(KpointAbstract):
|
|
|
751
751
|
|
|
752
752
|
|
|
753
753
|
|
|
754
|
-
def get_transformed_copy(self, symmetry_operation, k_new=None):
|
|
754
|
+
def get_transformed_copy(self, symmetry_operation, k_new=None, store=False):
|
|
755
755
|
"""
|
|
756
756
|
Get a copy of the k-point transformed by a symmetry operation.
|
|
757
757
|
|
|
@@ -1010,8 +1010,6 @@ class Kpoint(KpointAbstract):
|
|
|
1010
1010
|
igmax = igall.max(axis=0)
|
|
1011
1011
|
igmin = igall.min(axis=0)
|
|
1012
1012
|
igsize = igmax - igmin + 1
|
|
1013
|
-
# print (self.ig.T)
|
|
1014
|
-
# print (igsize)
|
|
1015
1013
|
res = np.zeros((self.num_bands, other.num_bands), dtype=complex)
|
|
1016
1014
|
|
|
1017
1015
|
# short again coefficients of expansions
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import numpy as np
|
|
2
|
+
|
|
3
|
+
from irrep.storage import DummyStorage
|
|
2
4
|
from .kpoint import KpointAbstract
|
|
3
5
|
from .utility import cached_einsum
|
|
4
6
|
from .parsers import ParserGPAW
|
|
@@ -24,35 +26,33 @@ class KpointGPAW(KpointAbstract):
|
|
|
24
26
|
RecLattice=None,
|
|
25
27
|
atom_positions=None):
|
|
26
28
|
super().__init__(kpt=kpt, num_bands=nbands, RecLattice=RecLattice)
|
|
27
|
-
self.
|
|
29
|
+
self._wavefunction = wavefunction
|
|
28
30
|
self.proj = proj
|
|
29
31
|
self.nbands = nbands
|
|
30
32
|
self.atom_positions = atom_positions
|
|
31
33
|
|
|
32
34
|
@classmethod
|
|
33
35
|
def from_gpaw(self, calc, ibz_index, ispin, RecLattice,
|
|
34
|
-
IBstart, IBend
|
|
36
|
+
IBstart, IBend,
|
|
37
|
+
storage, legacy_gpaw=None
|
|
35
38
|
):
|
|
39
|
+
from .parsers.gpaw import read_gpaw_wf
|
|
36
40
|
ispin = ParserGPAW.spin_channels[ispin]
|
|
37
|
-
|
|
38
|
-
k =
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
atom_positions = calc.atoms.get_scaled_positions()
|
|
46
|
-
|
|
47
|
-
wavefunction = np.array([calc.wfs.get_wave_function_array(n, ibz_index, ispin, periodic=True)
|
|
48
|
-
for n in range(IBstart, IBend)])
|
|
49
|
-
return KpointGPAW(kpt=k, wavefunction=wavefunction, proj=proj, nbands=nbands,
|
|
41
|
+
|
|
42
|
+
k, proj, wavefunction, RecLattice, atom_positions = read_gpaw_wf(
|
|
43
|
+
calc=calc, ibz_index=ibz_index, ispin=ispin, IBstart=IBstart, IBend=IBend, RecLattice=RecLattice,
|
|
44
|
+
legacy_gpaw=legacy_gpaw)
|
|
45
|
+
|
|
46
|
+
wavefunction = storage.store_array(wavefunction)
|
|
47
|
+
|
|
48
|
+
return KpointGPAW(kpt=k, wavefunction=wavefunction, proj=proj, nbands=IBend - IBstart,
|
|
50
49
|
RecLattice=RecLattice,
|
|
51
50
|
atom_positions=atom_positions)
|
|
52
51
|
|
|
52
|
+
def get_wavefunction(self):
|
|
53
|
+
return self._wavefunction.get()
|
|
53
54
|
|
|
54
|
-
|
|
55
|
-
def get_transformed_copy(self, symmetry_operation, k_new):
|
|
55
|
+
def get_transformed_copy(self, symmetry_operation, k_new, store=False):
|
|
56
56
|
"""Get a transformed copy of the KpointGPAW object according to the given symmetry operation.
|
|
57
57
|
|
|
58
58
|
Args:
|
|
@@ -62,21 +62,27 @@ class KpointGPAW(KpointAbstract):
|
|
|
62
62
|
Returns:
|
|
63
63
|
KpointGPAW: Transformed copy of the KpointGPAW object.
|
|
64
64
|
"""
|
|
65
|
-
new_wavefunction = symmetry_operation.rotate_pseudo_wavefunction(psi_n_grid=self.
|
|
65
|
+
new_wavefunction = symmetry_operation.rotate_pseudo_wavefunction(psi_n_grid=self.get_wavefunction(), k_origin=self.k, k_target=k_new)
|
|
66
66
|
new_proj = symmetry_operation.rotate_projection(self.proj, self.k, k_new)
|
|
67
|
+
if store:
|
|
68
|
+
storage = self._wavefunction.storage
|
|
69
|
+
else:
|
|
70
|
+
storage = DummyStorage()
|
|
71
|
+
new_wavefunction = storage.store_array(new_wavefunction)
|
|
67
72
|
return KpointGPAW(kpt=k_new, wavefunction=new_wavefunction, proj=new_proj, nbands=self.nbands,
|
|
68
|
-
RecLattice=self.RecLattice, atom_positions=self.atom_positions
|
|
73
|
+
RecLattice=self.RecLattice, atom_positions=self.atom_positions,
|
|
74
|
+
)
|
|
69
75
|
|
|
70
76
|
|
|
71
77
|
class OverlapPAW:
|
|
72
78
|
|
|
73
79
|
def __init__(self, calc, get_soc=True):
|
|
74
|
-
|
|
75
80
|
self.dO_aii = {}
|
|
76
81
|
for a, setup in enumerate(calc.wfs.setups):
|
|
77
82
|
self.dO_aii[a] = np.copy(setup.dO_ii)
|
|
78
83
|
self.orb_atom_indices = np.cumsum([0] + [dO.shape[0] for dO in self.dO_aii.values()])
|
|
79
|
-
|
|
84
|
+
from ase.units import Bohr
|
|
85
|
+
self.dv = np.copy(calc.wfs.gd.dv) * Bohr ** 3
|
|
80
86
|
if get_soc:
|
|
81
87
|
from gpaw.spinorbit import soc
|
|
82
88
|
self.dVL_avii = [
|
|
@@ -96,9 +102,12 @@ class OverlapPAW:
|
|
|
96
102
|
include_pseudo=True,
|
|
97
103
|
bk=None,
|
|
98
104
|
):
|
|
99
|
-
|
|
105
|
+
if bk is None:
|
|
106
|
+
bk = np.zeros(3)
|
|
107
|
+
assert np.allclose(KP2.k - KP1.k, bk), f"K-points must differ by bk for overlap calculation, but KP1={KP1.k}, KP2={KP2.k}, KP2.k - KP1.k = {KP2.k - KP1.k}, bk={bk}"
|
|
108
|
+
wf1 = KP1.get_wavefunction()
|
|
100
109
|
proj1 = KP1.proj
|
|
101
|
-
wf2 = KP2.
|
|
110
|
+
wf2 = KP2.get_wavefunction()
|
|
102
111
|
proj2 = KP2.proj
|
|
103
112
|
assert wf1.ndim == 4
|
|
104
113
|
assert wf2.ndim == 4
|
|
@@ -107,12 +116,7 @@ class OverlapPAW:
|
|
|
107
116
|
if include_pseudo:
|
|
108
117
|
prod += cached_einsum('aijk,bijk->ab', wf1.conj(), wf2) * self.dv
|
|
109
118
|
if include_paw:
|
|
110
|
-
|
|
111
|
-
na = len(positions)
|
|
112
|
-
if bk is None:
|
|
113
|
-
phases = np.ones(na, dtype=complex)
|
|
114
|
-
else:
|
|
115
|
-
phases = np.exp(-2j * np.pi * (positions @ bk))
|
|
119
|
+
phases = np.exp(-2j * np.pi * (KP1.atom_positions @ bk))
|
|
116
120
|
for a, dO_ii in self.dO_aii.items():
|
|
117
121
|
I1, I2 = self.get_orb_indices_on_atom(a)
|
|
118
122
|
prod += (proj1[:, I1:I2].conj() @ dO_ii @ (proj2[:, I1:I2].T)) * phases[a]
|
|
@@ -121,6 +125,7 @@ class OverlapPAW:
|
|
|
121
125
|
|
|
122
126
|
def soc(self, KP1, KP2):
|
|
123
127
|
from ase.units import Hartree
|
|
128
|
+
assert np.allclose(KP1.k, KP2.k), "K-points must be at the same coordinate for SOC calculation"
|
|
124
129
|
dVsoc = np.zeros((3, KP1.nbands, KP2.nbands), dtype=complex)
|
|
125
130
|
for a, dVL_vii in enumerate(self.dVL_avii):
|
|
126
131
|
I1, I2 = self.get_orb_indices_on_atom(a)
|
|
@@ -135,7 +135,6 @@ class ParserEspresso(ParserCommon):
|
|
|
135
135
|
checked_files = []
|
|
136
136
|
for extension in ["hdf5", "dat"]:
|
|
137
137
|
for strcase in [str.lower, str.upper]:
|
|
138
|
-
print(f"{ik=}, {wfcname=}, {extension=}, {strcase=}")
|
|
139
138
|
filename = f"{self.prefix}.save/{strcase(wfcname)}.{extension}"
|
|
140
139
|
if os.path.exists(filename):
|
|
141
140
|
if extension == "hdf5":
|
|
@@ -103,11 +103,12 @@ class ParserGPAW(ParserCommon):
|
|
|
103
103
|
return energies, WFout, kg, kpt, eKG
|
|
104
104
|
|
|
105
105
|
|
|
106
|
-
def get_soc_gpaw(calc, ik, flatten=True, theta=0, phi=0):
|
|
106
|
+
def get_soc_gpaw(calc, ik, flatten=True, theta=0, phi=0, legacy_gpaw=None):
|
|
107
107
|
"""Calculate SOC Hamiltonian in KS basis for a given k-point."""
|
|
108
108
|
from ase.units import Hartree
|
|
109
109
|
from gpaw.spinorbit import soc
|
|
110
110
|
|
|
111
|
+
legacy_gpaw = check_legacy_gpaw(calc, legacy_gpaw)
|
|
111
112
|
nspin = calc.get_number_of_spins()
|
|
112
113
|
|
|
113
114
|
C_ss = np.array(
|
|
@@ -150,12 +151,21 @@ def get_soc_gpaw(calc, ik, flatten=True, theta=0, phi=0):
|
|
|
150
151
|
for s1 in range(2):
|
|
151
152
|
for s2 in range(2):
|
|
152
153
|
h_ii = h_ssii[s1, s2]
|
|
153
|
-
if
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
154
|
+
if legacy_gpaw:
|
|
155
|
+
if nspin == 2:
|
|
156
|
+
P1_mi = calc.wfs.kpt_qs[q][s1].P_ani[a]
|
|
157
|
+
P2_mi = calc.wfs.kpt_qs[q][s2].P_ani[a]
|
|
158
|
+
else:
|
|
159
|
+
P1_mi = calc.wfs.kpt_qs[q][0].P_ani[a]
|
|
160
|
+
P2_mi = P1_mi
|
|
161
|
+
else:
|
|
162
|
+
if nspin == 2:
|
|
163
|
+
# maybe need to use get_wfs_on_master for parallel runs, but needs testing
|
|
164
|
+
P1_mi = calc.dft.ibzwfs._get_wfs(kpt=q, spin=s1).P_ani[a]
|
|
165
|
+
P2_mi = calc.dft.ibzwfs._get_wfs(kpt=q, spin=s2).P_ani[a]
|
|
166
|
+
else:
|
|
167
|
+
P1_mi = calc.dft.ibzwfs._get_wfs(kpt=q, spin=0).P_ani[a]
|
|
168
|
+
P2_mi = P1_mi
|
|
159
169
|
|
|
160
170
|
h_soc[s1, s2] += np.dot(np.dot(P1_mi.conj(), h_ii), P2_mi.T)
|
|
161
171
|
if flatten:
|
|
@@ -165,3 +175,69 @@ def get_soc_gpaw(calc, ik, flatten=True, theta=0, phi=0):
|
|
|
165
175
|
for s2 in range(2):
|
|
166
176
|
h_soc[s1::2, s2::2] = h_soc_old[s1, s2]
|
|
167
177
|
return h_soc * Hartree
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def check_legacy_gpaw(calc, legacy_gpaw=None):
|
|
181
|
+
if legacy_gpaw is not None:
|
|
182
|
+
return legacy_gpaw
|
|
183
|
+
else:
|
|
184
|
+
return not is_new_gpaw(calc)
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def is_new_gpaw(calc):
|
|
188
|
+
# "New GPAW" (default in 26): ASECalculator exposing .dft
|
|
189
|
+
# Legacy calculator (25.x, or 26 with legacy_gpaw=True): real calc.wfs
|
|
190
|
+
if hasattr(calc, '_wfs_dft'):
|
|
191
|
+
return True
|
|
192
|
+
if hasattr(calc, 'get_realspace_wfs'):
|
|
193
|
+
return False
|
|
194
|
+
raise ValueError("Cannot determine if GPAW is new or legacy. Please check the GPAW version and calculator type.")
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def is_collinear(calc):
|
|
199
|
+
if hasattr(calc, 'dft'): # new GPAW (26 default)
|
|
200
|
+
return calc.dft.ibzwfs.collinear
|
|
201
|
+
return calc.wfs.collinear
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def get_magnetic_moments(calc, project_collinear_axis=(0, 0, 1), legacy_gpaw=None):
|
|
205
|
+
legacy_gpaw = check_legacy_gpaw(calc, legacy_gpaw)
|
|
206
|
+
if legacy_gpaw:
|
|
207
|
+
magmoms = calc.get_magnetic_moments()
|
|
208
|
+
else:
|
|
209
|
+
magmoms = calc.dft.magmoms()[1]
|
|
210
|
+
if is_collinear(calc) and project_collinear_axis:
|
|
211
|
+
magmoms = np.dot(magmoms, project_collinear_axis)
|
|
212
|
+
return magmoms
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
@staticmethod
|
|
216
|
+
def read_gpaw_wf(calc, ibz_index, ispin, IBstart, IBend, RecLattice, legacy_gpaw=None):
|
|
217
|
+
legacy_gpaw = check_legacy_gpaw(calc, legacy_gpaw)
|
|
218
|
+
k = calc.get_ibz_k_points()[ibz_index]
|
|
219
|
+
|
|
220
|
+
if legacy_gpaw:
|
|
221
|
+
P_ani = calc.wfs.kpt_qs[ibz_index][ispin].P_ani
|
|
222
|
+
if RecLattice is None:
|
|
223
|
+
RecLattice = calc.wfs.gd.reciprocal_lattice
|
|
224
|
+
wavefunction = np.array([
|
|
225
|
+
calc.wfs.get_wave_function_array(n, ibz_index, ispin, periodic=True)
|
|
226
|
+
for n in range(IBstart, IBend)])
|
|
227
|
+
from ase.units import Bohr
|
|
228
|
+
wavefunction /= Bohr ** 1.5
|
|
229
|
+
else:
|
|
230
|
+
wfs = calc.dft.ibzwfs._get_wfs(kpt=ibz_index, spin=ispin)
|
|
231
|
+
P_ani = wfs.P_ani.to_cpu() # AtomArrays; P_ani[a] -> (nbands, nproj_a)
|
|
232
|
+
wavefunction = calc.dft.wave_functions(n1=IBstart, n2=IBend, kpt=ibz_index, spin=ispin, periodic=True).data
|
|
233
|
+
# from ase.units import Bohr
|
|
234
|
+
# wavefunction *= Bohr ** 1.5
|
|
235
|
+
|
|
236
|
+
if RecLattice is None:
|
|
237
|
+
RecLattice = 2 * np.pi * np.linalg.inv(calc.atoms.cell.array).T # check units vs 25.7
|
|
238
|
+
|
|
239
|
+
proj = np.hstack([P_ani[a][IBstart:IBend] for a in range(len(calc.atoms))])
|
|
240
|
+
|
|
241
|
+
atom_positions = calc.atoms.get_scaled_positions()
|
|
242
|
+
|
|
243
|
+
return k, proj, wavefunction, RecLattice, atom_positions
|
|
@@ -21,10 +21,11 @@ import warnings
|
|
|
21
21
|
import numpy as np
|
|
22
22
|
import spglib
|
|
23
23
|
|
|
24
|
-
from
|
|
24
|
+
from .parsers import ParserAbinit, ParserEspresso, ParserVasp, ParserW90
|
|
25
|
+
from .parsers.gpaw import get_magnetic_moments
|
|
25
26
|
|
|
26
27
|
from .symmetry_operation import SymmetryOperation
|
|
27
|
-
from .utility import BOHR, group_numbers, log_message, select_irreducible
|
|
28
|
+
from .utility import BOHR, clean_np_load, group_numbers, log_message, select_irreducible
|
|
28
29
|
from packaging import version
|
|
29
30
|
import os
|
|
30
31
|
|
|
@@ -226,6 +227,27 @@ class SpaceGroup:
|
|
|
226
227
|
dic[key] = val
|
|
227
228
|
return dic
|
|
228
229
|
|
|
230
|
+
@classmethod
|
|
231
|
+
def from_dict(cls, dic):
|
|
232
|
+
"""
|
|
233
|
+
Create a SpaceGroup object from a dictionary.
|
|
234
|
+
"""
|
|
235
|
+
dic_clean = clean_np_load(dic)
|
|
236
|
+
return cls(**dic_clean)
|
|
237
|
+
|
|
238
|
+
@classmethod
|
|
239
|
+
def from_npz(cls, file_path):
|
|
240
|
+
"""
|
|
241
|
+
Create a SpaceGroup object from a .npz file.
|
|
242
|
+
"""
|
|
243
|
+
return cls.from_dict(np.load(file_path, allow_pickle=True))
|
|
244
|
+
|
|
245
|
+
def to_npz(self, file_path):
|
|
246
|
+
"""
|
|
247
|
+
Save the SpaceGroup object to a .npz file.
|
|
248
|
+
"""
|
|
249
|
+
np.savez(file_path, **self.as_dict())
|
|
250
|
+
|
|
229
251
|
@property
|
|
230
252
|
def size(self):
|
|
231
253
|
"""
|
|
@@ -233,7 +255,7 @@ class SpaceGroup:
|
|
|
233
255
|
"""
|
|
234
256
|
return len(self.symmetries)
|
|
235
257
|
|
|
236
|
-
def show(self, symmetries=None):
|
|
258
|
+
def show(self, symmetries=None, short=False, to_stdout=True):
|
|
237
259
|
"""
|
|
238
260
|
Print description of space-group and symmetry operations.
|
|
239
261
|
|
|
@@ -244,27 +266,26 @@ class SpaceGroup:
|
|
|
244
266
|
Run `IrRep` with flag `onlysym` to check the index corresponding
|
|
245
267
|
to each symmetry operation.
|
|
246
268
|
"""
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
# Print cell vectors in DFT cell only
|
|
253
|
-
print('Cell vectors in angstroms:\n')
|
|
254
|
-
print(f"{'Vectors of DFT cell':^32}")
|
|
269
|
+
out_str = ""
|
|
270
|
+
if not short:
|
|
271
|
+
out_str += "\n ---------- CRYSTAL STRUCTURE ---------- \n\n"
|
|
272
|
+
out_str += 'Cell vectors in angstroms:\n\n'
|
|
273
|
+
out_str += f'{"Vectors of DFT cell":^32}\n'
|
|
255
274
|
for i in range(3):
|
|
256
275
|
vec1 = self.real_lattice[i]
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
print(f'Number of symmetries: {self.size} (mod. lattice translations)')
|
|
276
|
+
out_str += f'a{i:d} = {vec1[0]:7.4f} {vec1[1]:7.4f} {vec1[2]:7.4f} \n'
|
|
277
|
+
out_str += '\n'
|
|
278
|
+
|
|
279
|
+
if not short:
|
|
280
|
+
out_str += '\n ---------- SPACE GROUP ----------- \n\n'
|
|
281
|
+
out_str += f'Space group: {self.name} (# {self.number_str})\n'
|
|
282
|
+
out_str += f'Number of symmetries: {self.size} (mod. lattice translations)\n'
|
|
265
283
|
for symop in self.symmetries:
|
|
266
284
|
if symmetries is None or symop.ind in symmetries:
|
|
267
|
-
symop.show(refUC=None, shiftUC=None)
|
|
285
|
+
out_str += symop.show(refUC=None, shiftUC=None, to_stdout=False, short=short) + '\n'
|
|
286
|
+
if to_stdout:
|
|
287
|
+
print(out_str)
|
|
288
|
+
return out_str
|
|
268
289
|
|
|
269
290
|
@property
|
|
270
291
|
def lattice(self):
|
|
@@ -882,6 +903,7 @@ class SpaceGroup:
|
|
|
882
903
|
magnetic=True,
|
|
883
904
|
spinor=None,
|
|
884
905
|
verbosity=0,
|
|
906
|
+
legacy_gpaw=None,
|
|
885
907
|
**kwargs_cell):
|
|
886
908
|
"""Get the spacegroup of a GPAW calculator (non-spinor only).
|
|
887
909
|
Parameters
|
|
@@ -913,7 +935,7 @@ class SpaceGroup:
|
|
|
913
935
|
typat = calculator.atoms.get_atomic_numbers()
|
|
914
936
|
if magnetic:
|
|
915
937
|
if magmom is None:
|
|
916
|
-
magmom =
|
|
938
|
+
magmom = get_magnetic_moments(calculator, legacy_gpaw=legacy_gpaw)
|
|
917
939
|
assert magmom.shape == (len(calculator.atoms),)
|
|
918
940
|
else:
|
|
919
941
|
magmom = np.zeros(len(calculator.atoms), dtype=float)
|
|
@@ -933,50 +955,6 @@ class SpaceGroup:
|
|
|
933
955
|
**kwargs_cell
|
|
934
956
|
)
|
|
935
957
|
|
|
936
|
-
# @classmethod
|
|
937
|
-
# def from_gpaw_magnetic(cls, calculator, theta=0, phi=0, include_TR=True,
|
|
938
|
-
# magmom=None, magmoms=None,
|
|
939
|
-
# mag_symprec=0.05, symprec=1e-5,
|
|
940
|
-
# ):
|
|
941
|
-
# """
|
|
942
|
-
# Get the spacegroup of a GPAW calculator (spinor magnetic version).
|
|
943
|
-
|
|
944
|
-
# Parameters:
|
|
945
|
-
# calculator : GPAW
|
|
946
|
-
# The GPAW calculator.
|
|
947
|
-
# theta, phi : float
|
|
948
|
-
# The angles defining the global spin quantization axis. (in radians)
|
|
949
|
-
# magnetic moments will be aligned along that direction (in positive or negative direction, as defined from dft calculation)
|
|
950
|
-
# include_TR : bool
|
|
951
|
-
# Whether to include time-reversal symmetry.
|
|
952
|
-
# magmom : array( Nat, 3), optional
|
|
953
|
-
# if provided, overrides the magnetic moments of the calculator
|
|
954
|
-
# magmoms : array(Nat,), optional
|
|
955
|
-
# The older argument for magmom, kept for backward compatibility. Used only if magmom is None.
|
|
956
|
-
# mag_symprec : float
|
|
957
|
-
# The precision for distinguishing different magnetic moments. Only used if magmom is None.
|
|
958
|
-
# symprec : float
|
|
959
|
-
# The symmetry precision for spacegroup detection.
|
|
960
|
-
# """
|
|
961
|
-
# lattice = calculator.atoms.cell
|
|
962
|
-
# typat = calculator.atoms.get_atomic_numbers()
|
|
963
|
-
# positions = calculator.atoms.get_scaled_positions()
|
|
964
|
-
# if magmom is None:
|
|
965
|
-
# magmom = magmoms
|
|
966
|
-
# if magmom is None:
|
|
967
|
-
# magmom_axis = calculator.get_magnetic_moments()
|
|
968
|
-
# magmom_axis = group_numbers(magmom_axis, precision=mag_symprec)
|
|
969
|
-
# axis = np.array([np.sin(theta) * np.cos(phi), np.sin(theta) * np.sin(phi), np.cos(theta)])
|
|
970
|
-
# magmom = magmom_axis[:, None] * axis[None, :]
|
|
971
|
-
# print(f"using magmom \n {magmom}")
|
|
972
|
-
# return SpaceGroup.from_cell(real_lattice=lattice,
|
|
973
|
-
# positions=positions,
|
|
974
|
-
# typat=typat,
|
|
975
|
-
# spinor=True,
|
|
976
|
-
# include_TR=include_TR,
|
|
977
|
-
# symprec=symprec,
|
|
978
|
-
# mag_symprec=mag_symprec,
|
|
979
|
-
# magmom=magmom)
|
|
980
958
|
|
|
981
959
|
@classmethod
|
|
982
960
|
def get_trivial(cls, lattice, spinor=False, time_reversal=False):
|