irrep 3.3.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.3.0 → irrep-3.4.0}/PKG-INFO +1 -1
- {irrep-3.3.0 → irrep-3.4.0}/irrep/_version.py +3 -3
- {irrep-3.3.0 → irrep-3.4.0}/irrep/bandstructure.py +3 -1
- {irrep-3.3.0 → irrep-3.4.0}/irrep/kpoint.py +0 -2
- {irrep-3.3.0 → irrep-3.4.0}/irrep/kpoint_gpaw.py +15 -22
- {irrep-3.3.0 → irrep-3.4.0}/irrep/parsers/espresso.py +0 -1
- {irrep-3.3.0 → irrep-3.4.0}/irrep/parsers/gpaw.py +83 -7
- {irrep-3.3.0 → irrep-3.4.0}/irrep/spacegroup.py +21 -64
- {irrep-3.3.0 → irrep-3.4.0}/irrep/symmetry_operation.py +39 -26
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/conftest.py +13 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_gpaw.py +43 -16
- irrep-3.4.0/irrep/tests/test_gpaw_vs_legacy.py +46 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_paw.py +39 -13
- {irrep-3.3.0 → irrep-3.4.0}/irrep.egg-info/PKG-INFO +1 -1
- {irrep-3.3.0 → irrep-3.4.0}/irrep.egg-info/SOURCES.txt +1 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep.egg-info/scm_file_list.json +12 -6
- irrep-3.4.0/irrep.egg-info/scm_version.json +8 -0
- irrep-3.3.0/.github/workflows/tests.yml +0 -42
- irrep-3.3.0/irrep.egg-info/scm_version.json +0 -8
- {irrep-3.3.0 → irrep-3.4.0}/.github/workflows/python-publish.yml +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/.gitignore +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/INSTALL +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/LICENSE +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/MANIFEST.in +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/README.md +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/__init__.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/altermagnetic_transformer.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/cli.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/data/msg_numbers.data +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/ebrs.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/gvectors.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/or_solutions_obtainer.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/parsers/__init__.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/parsers/abinit.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/parsers/common.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/parsers/parse_files_bandstructure.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/parsers/vasp.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/parsers/wannier90.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/spacegroup_irreps.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/storage.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/__init__.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/ref_data/Fe_qe_dmn_TR=False.pkl +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/ref_data/Fe_qe_dmn_TR=False_irred.pkl +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/ref_data/Fe_qe_dmn_TR=True.pkl +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/ref_data/Fe_qe_dmn_TR=True_irred.pkl +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/ref_data/magmom_Fe_qe_dmn.txt +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/ref_data/spacegroup_Te_TR.npz +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/ref_data/spacegroup_Te_TR_product.npz +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/ref_data/spacegroup_Te_noTR.npz +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/ref_data/spacegroup_Te_noTR_product.npz +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/ref_data/symm_matrix_block.npz +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/ref_data/symm_matrix_full.npz +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_abinit_scalar.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_abinit_spinor.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_altermagnetic.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_dmn.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_ebr_decomposition.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_espresso_hdf5.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_espresso_spinor.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_espresso_spinpol.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_refUC.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_spacegroup.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_symmetry_indicators.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_symsep.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_vasp_scalar.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_vasp_spinor.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_wannier_scalar.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/tests/test_wannier_spinor.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep/utility.py +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep.egg-info/dependency_links.txt +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep.egg-info/entry_points.txt +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep.egg-info/requires.txt +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/irrep.egg-info/top_level.txt +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/pyproject.toml +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/setup.cfg +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi/POSCAR +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi/README.md +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi/WAVECAR +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi/images/bands.png +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi/images/checktopomat.png +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi/inputs_maxK/INCAR +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi/inputs_maxK/KPOINTS +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi/inputs_maxK/POSCAR +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi/inputs_maxK/POTCAR +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi/inputs_scf/INCAR +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi/inputs_scf/KPOINTS +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi/inputs_scf/POSCAR +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi/inputs_scf/POTCAR +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/README.md +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/images/bands.png +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/images/checktopomat.png +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/inputs/Bi.txt +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/inputs/Se.txt +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/inputs/bands.in +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/inputs/nscf_IrRep.in +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/inputs/pp.bands.in +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/inputs/scf.in +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/charge-density.dat +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/data-file-schema.xml +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/paw.txt +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/wfc1.dat +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/wfc2.dat +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/wfc3.dat +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.save/wfc4.dat +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/Bi2Se3/out/Bi2Se3.xml +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/SnTe/README.md +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/SnTe/images/bands.png +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/SnTe/images/checktopomat.png +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/SnTe/images/refUC.png +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/SnTe/inputs/Sn.xml +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/SnTe/inputs/Te.xml +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/SnTe/inputs/parameters.in +0 -0
- {irrep-3.3.0 → irrep-3.4.0}/tutorial/SnTe/maxK_WFK +0 -0
- {irrep-3.3.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'
|
|
@@ -22,7 +22,7 @@ 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
|
|
@@ -531,8 +531,10 @@ class BandStructure:
|
|
|
531
531
|
read_paw=False,
|
|
532
532
|
store_paw=True,
|
|
533
533
|
storage="tmp_irrep_storage",
|
|
534
|
+
legacy_gpaw=None,
|
|
534
535
|
**kwargs
|
|
535
536
|
):
|
|
537
|
+
legacy_gpaw = check_legacy_gpaw(legacy_gpaw, calculator_gpaw)
|
|
536
538
|
|
|
537
539
|
if spacegroup is None:
|
|
538
540
|
cls_spacegroup, kwargs_spacegroup = cls.get_spacegroup_cls(spin_channel=spin_channel, irreps=irreps, **kwargs)
|
|
@@ -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
|
|
@@ -34,24 +34,18 @@ class KpointGPAW(KpointAbstract):
|
|
|
34
34
|
@classmethod
|
|
35
35
|
def from_gpaw(self, calc, ibz_index, ispin, RecLattice,
|
|
36
36
|
IBstart, IBend,
|
|
37
|
-
storage
|
|
37
|
+
storage, legacy_gpaw=None
|
|
38
38
|
):
|
|
39
|
+
from .parsers.gpaw import read_gpaw_wf
|
|
39
40
|
ispin = ParserGPAW.spin_channels[ispin]
|
|
40
|
-
|
|
41
|
-
k =
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
# Get projections in ibz
|
|
46
|
-
if RecLattice is None:
|
|
47
|
-
RecLattice = calc.wfs.gd.reciprocal_lattice
|
|
48
|
-
atom_positions = calc.atoms.get_scaled_positions()
|
|
49
|
-
|
|
50
|
-
wavefunction = np.array([calc.wfs.get_wave_function_array(n, ibz_index, ispin, periodic=True)
|
|
51
|
-
for n in range(IBstart, IBend)])
|
|
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
|
+
|
|
52
46
|
wavefunction = storage.store_array(wavefunction)
|
|
53
47
|
|
|
54
|
-
return KpointGPAW(kpt=k, wavefunction=wavefunction, proj=proj, nbands=
|
|
48
|
+
return KpointGPAW(kpt=k, wavefunction=wavefunction, proj=proj, nbands=IBend - IBstart,
|
|
55
49
|
RecLattice=RecLattice,
|
|
56
50
|
atom_positions=atom_positions)
|
|
57
51
|
|
|
@@ -83,12 +77,12 @@ class KpointGPAW(KpointAbstract):
|
|
|
83
77
|
class OverlapPAW:
|
|
84
78
|
|
|
85
79
|
def __init__(self, calc, get_soc=True):
|
|
86
|
-
|
|
87
80
|
self.dO_aii = {}
|
|
88
81
|
for a, setup in enumerate(calc.wfs.setups):
|
|
89
82
|
self.dO_aii[a] = np.copy(setup.dO_ii)
|
|
90
83
|
self.orb_atom_indices = np.cumsum([0] + [dO.shape[0] for dO in self.dO_aii.values()])
|
|
91
|
-
|
|
84
|
+
from ase.units import Bohr
|
|
85
|
+
self.dv = np.copy(calc.wfs.gd.dv) * Bohr ** 3
|
|
92
86
|
if get_soc:
|
|
93
87
|
from gpaw.spinorbit import soc
|
|
94
88
|
self.dVL_avii = [
|
|
@@ -108,6 +102,9 @@ class OverlapPAW:
|
|
|
108
102
|
include_pseudo=True,
|
|
109
103
|
bk=None,
|
|
110
104
|
):
|
|
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}"
|
|
111
108
|
wf1 = KP1.get_wavefunction()
|
|
112
109
|
proj1 = KP1.proj
|
|
113
110
|
wf2 = KP2.get_wavefunction()
|
|
@@ -119,12 +116,7 @@ class OverlapPAW:
|
|
|
119
116
|
if include_pseudo:
|
|
120
117
|
prod += cached_einsum('aijk,bijk->ab', wf1.conj(), wf2) * self.dv
|
|
121
118
|
if include_paw:
|
|
122
|
-
|
|
123
|
-
na = len(positions)
|
|
124
|
-
if bk is None:
|
|
125
|
-
phases = np.ones(na, dtype=complex)
|
|
126
|
-
else:
|
|
127
|
-
phases = np.exp(-2j * np.pi * (positions @ bk))
|
|
119
|
+
phases = np.exp(-2j * np.pi * (KP1.atom_positions @ bk))
|
|
128
120
|
for a, dO_ii in self.dO_aii.items():
|
|
129
121
|
I1, I2 = self.get_orb_indices_on_atom(a)
|
|
130
122
|
prod += (proj1[:, I1:I2].conj() @ dO_ii @ (proj2[:, I1:I2].T)) * phases[a]
|
|
@@ -133,6 +125,7 @@ class OverlapPAW:
|
|
|
133
125
|
|
|
134
126
|
def soc(self, KP1, KP2):
|
|
135
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"
|
|
136
129
|
dVsoc = np.zeros((3, KP1.nbands, KP2.nbands), dtype=complex)
|
|
137
130
|
for a, dVL_vii in enumerate(self.dVL_avii):
|
|
138
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,7 +21,8 @@ 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
28
|
from .utility import BOHR, clean_np_load, group_numbers, log_message, select_irreducible
|
|
@@ -254,7 +255,7 @@ class SpaceGroup:
|
|
|
254
255
|
"""
|
|
255
256
|
return len(self.symmetries)
|
|
256
257
|
|
|
257
|
-
def show(self, symmetries=None):
|
|
258
|
+
def show(self, symmetries=None, short=False, to_stdout=True):
|
|
258
259
|
"""
|
|
259
260
|
Print description of space-group and symmetry operations.
|
|
260
261
|
|
|
@@ -265,27 +266,26 @@ class SpaceGroup:
|
|
|
265
266
|
Run `IrRep` with flag `onlysym` to check the index corresponding
|
|
266
267
|
to each symmetry operation.
|
|
267
268
|
"""
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
# Print cell vectors in DFT cell only
|
|
274
|
-
print('Cell vectors in angstroms:\n')
|
|
275
|
-
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'
|
|
276
274
|
for i in range(3):
|
|
277
275
|
vec1 = self.real_lattice[i]
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
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'
|
|
286
283
|
for symop in self.symmetries:
|
|
287
284
|
if symmetries is None or symop.ind in symmetries:
|
|
288
|
-
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
|
|
289
289
|
|
|
290
290
|
@property
|
|
291
291
|
def lattice(self):
|
|
@@ -903,6 +903,7 @@ class SpaceGroup:
|
|
|
903
903
|
magnetic=True,
|
|
904
904
|
spinor=None,
|
|
905
905
|
verbosity=0,
|
|
906
|
+
legacy_gpaw=None,
|
|
906
907
|
**kwargs_cell):
|
|
907
908
|
"""Get the spacegroup of a GPAW calculator (non-spinor only).
|
|
908
909
|
Parameters
|
|
@@ -934,7 +935,7 @@ class SpaceGroup:
|
|
|
934
935
|
typat = calculator.atoms.get_atomic_numbers()
|
|
935
936
|
if magnetic:
|
|
936
937
|
if magmom is None:
|
|
937
|
-
magmom =
|
|
938
|
+
magmom = get_magnetic_moments(calculator, legacy_gpaw=legacy_gpaw)
|
|
938
939
|
assert magmom.shape == (len(calculator.atoms),)
|
|
939
940
|
else:
|
|
940
941
|
magmom = np.zeros(len(calculator.atoms), dtype=float)
|
|
@@ -954,50 +955,6 @@ class SpaceGroup:
|
|
|
954
955
|
**kwargs_cell
|
|
955
956
|
)
|
|
956
957
|
|
|
957
|
-
# @classmethod
|
|
958
|
-
# def from_gpaw_magnetic(cls, calculator, theta=0, phi=0, include_TR=True,
|
|
959
|
-
# magmom=None, magmoms=None,
|
|
960
|
-
# mag_symprec=0.05, symprec=1e-5,
|
|
961
|
-
# ):
|
|
962
|
-
# """
|
|
963
|
-
# Get the spacegroup of a GPAW calculator (spinor magnetic version).
|
|
964
|
-
|
|
965
|
-
# Parameters:
|
|
966
|
-
# calculator : GPAW
|
|
967
|
-
# The GPAW calculator.
|
|
968
|
-
# theta, phi : float
|
|
969
|
-
# The angles defining the global spin quantization axis. (in radians)
|
|
970
|
-
# magnetic moments will be aligned along that direction (in positive or negative direction, as defined from dft calculation)
|
|
971
|
-
# include_TR : bool
|
|
972
|
-
# Whether to include time-reversal symmetry.
|
|
973
|
-
# magmom : array( Nat, 3), optional
|
|
974
|
-
# if provided, overrides the magnetic moments of the calculator
|
|
975
|
-
# magmoms : array(Nat,), optional
|
|
976
|
-
# The older argument for magmom, kept for backward compatibility. Used only if magmom is None.
|
|
977
|
-
# mag_symprec : float
|
|
978
|
-
# The precision for distinguishing different magnetic moments. Only used if magmom is None.
|
|
979
|
-
# symprec : float
|
|
980
|
-
# The symmetry precision for spacegroup detection.
|
|
981
|
-
# """
|
|
982
|
-
# lattice = calculator.atoms.cell
|
|
983
|
-
# typat = calculator.atoms.get_atomic_numbers()
|
|
984
|
-
# positions = calculator.atoms.get_scaled_positions()
|
|
985
|
-
# if magmom is None:
|
|
986
|
-
# magmom = magmoms
|
|
987
|
-
# if magmom is None:
|
|
988
|
-
# magmom_axis = calculator.get_magnetic_moments()
|
|
989
|
-
# magmom_axis = group_numbers(magmom_axis, precision=mag_symprec)
|
|
990
|
-
# axis = np.array([np.sin(theta) * np.cos(phi), np.sin(theta) * np.sin(phi), np.cos(theta)])
|
|
991
|
-
# magmom = magmom_axis[:, None] * axis[None, :]
|
|
992
|
-
# print(f"using magmom \n {magmom}")
|
|
993
|
-
# return SpaceGroup.from_cell(real_lattice=lattice,
|
|
994
|
-
# positions=positions,
|
|
995
|
-
# typat=typat,
|
|
996
|
-
# spinor=True,
|
|
997
|
-
# include_TR=include_TR,
|
|
998
|
-
# symprec=symprec,
|
|
999
|
-
# mag_symprec=mag_symprec,
|
|
1000
|
-
# magmom=magmom)
|
|
1001
958
|
|
|
1002
959
|
@classmethod
|
|
1003
960
|
def get_trivial(cls, lattice, spinor=False, time_reversal=False):
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
##################################################################
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
from gpaw.rotation import rotation # rotation(l, U_vv) -> (2l+1, 2l+1)
|
|
18
19
|
from functools import cached_property
|
|
19
20
|
import warnings
|
|
20
21
|
import numpy as np
|
|
@@ -397,8 +398,15 @@ class SymmetryOperation():
|
|
|
397
398
|
S *= self.sign
|
|
398
399
|
return S
|
|
399
400
|
|
|
401
|
+
def show_short(self, to_stdout=False):
|
|
402
|
+
out_str = f"axis: {self.axis.round(6)} ; angle = {self.angle_str}, inversion: {self.inversion}, time reversal: {self.time_reversal}"
|
|
403
|
+
if to_stdout:
|
|
404
|
+
print(out_str)
|
|
405
|
+
return out_str
|
|
400
406
|
|
|
401
|
-
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
def show(self, refUC=np.eye(3), shiftUC=np.zeros(3), U=np.eye(2), to_stdout=True, short=False):
|
|
402
410
|
"""
|
|
403
411
|
Print description of symmetry operation.
|
|
404
412
|
|
|
@@ -413,7 +421,13 @@ class SymmetryOperation():
|
|
|
413
421
|
U : array, default=np.zeros(2)
|
|
414
422
|
Unitary transformation of spin quantization axis from spglib's
|
|
415
423
|
choice to reference cell's choice
|
|
424
|
+
print : bool, default=True
|
|
425
|
+
If True, print the description. If False, return it as a string.
|
|
426
|
+
short : bool, default=False
|
|
427
|
+
If True, print a short description. If False, print a full description.
|
|
416
428
|
"""
|
|
429
|
+
if short:
|
|
430
|
+
return self.show_short(to_stdout=to_stdout)
|
|
417
431
|
|
|
418
432
|
def parse_row_transform(mrow):
|
|
419
433
|
s = ""
|
|
@@ -447,7 +461,7 @@ class SymmetryOperation():
|
|
|
447
461
|
write_ref = False
|
|
448
462
|
|
|
449
463
|
# Print header
|
|
450
|
-
|
|
464
|
+
out_str = f"\n ### {self.ind} \n\n"
|
|
451
465
|
|
|
452
466
|
# Print rotation part
|
|
453
467
|
rotstr = [
|
|
@@ -486,8 +500,7 @@ class SymmetryOperation():
|
|
|
486
500
|
[parse_row_transform(r) for r in matrix]
|
|
487
501
|
) + "]"
|
|
488
502
|
|
|
489
|
-
|
|
490
|
-
print("\n\n", kstring)
|
|
503
|
+
out_str += "\n".join(rotstr) + "\n\n" + kstring + "\n"
|
|
491
504
|
|
|
492
505
|
# Print spinor transformation matrix
|
|
493
506
|
if self.spinor:
|
|
@@ -497,28 +510,32 @@ class SymmetryOperation():
|
|
|
497
510
|
self.spinor_rotation,
|
|
498
511
|
[" |", " |"])
|
|
499
512
|
]
|
|
500
|
-
|
|
513
|
+
out_str += "\n".join(spinstr) + "\n"
|
|
501
514
|
if write_ref:
|
|
502
515
|
spinstr = [s + " ".join(f"{x.real:6.3f}{x.imag:+6.3f}j" for x in row) + t
|
|
503
516
|
for s, row, t in zip(["spinor rot. (refUC) : |", " " * 22 + "|",],
|
|
504
517
|
self.spinrotation_refUC(U),
|
|
505
518
|
[" |", " |"])
|
|
506
519
|
]
|
|
507
|
-
|
|
520
|
+
out_str += "\n".join(spinstr) + "\n"
|
|
508
521
|
|
|
509
522
|
# Print translation part
|
|
510
523
|
trastr = ("\ntranslation : [ " +
|
|
511
524
|
" ".join(f"{x:8.4f}" for x in self.get_transl_mod1(self.translation.round(6))) +
|
|
512
525
|
" ] ")
|
|
513
|
-
|
|
526
|
+
out_str += trastr
|
|
514
527
|
|
|
515
528
|
if write_ref:
|
|
516
529
|
_t = self.translation_refUC(refUC, shiftUC)
|
|
517
530
|
trastr = f"translation (refUC) : [ {' '.join(f'{x:8.4f}' for x in self.get_transl_mod1(_t.round(6)))} ] "
|
|
518
|
-
|
|
531
|
+
out_str += trastr
|
|
532
|
+
out_str += "\n\n"
|
|
533
|
+
out_str += self.show_short(to_stdout=False) + "\n"
|
|
534
|
+
|
|
535
|
+
if to_stdout:
|
|
536
|
+
print(out_str)
|
|
537
|
+
return out_str
|
|
519
538
|
|
|
520
|
-
print(f"\naxis: {self.axis.round(6)} ; angle = {self.angle_str}, "
|
|
521
|
-
f"inversion: {self.inversion}, time reversal: {self.time_reversal}")
|
|
522
539
|
|
|
523
540
|
def copy(self):
|
|
524
541
|
"""
|
|
@@ -860,24 +877,20 @@ class SymmetryOperation():
|
|
|
860
877
|
def set_R_aii_gpaw(self, calc, reset=False):
|
|
861
878
|
"""rotation matrices for the PAW projections."""
|
|
862
879
|
if not hasattr(self, 'R_aii') or reset:
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
880
|
+
"""One block-diagonal projector-space rotation matrix per atom."""
|
|
881
|
+
self.R_aii = []
|
|
882
|
+
for id_ in calc.setups.id_a: # one entry per atom
|
|
883
|
+
setup = calc.setups.setups[id_] # dict: id -> Setup
|
|
884
|
+
n = sum(2 * l + 1 for l in setup.l_j)
|
|
885
|
+
R = np.zeros((n, n))
|
|
886
|
+
i = 0
|
|
887
|
+
for l in setup.l_j:
|
|
888
|
+
m = 2 * l + 1
|
|
889
|
+
R[i:i + m, i:i + m] = rotation(l, self.rotation_cart)
|
|
890
|
+
i += m
|
|
891
|
+
self.R_aii.append(R)
|
|
875
892
|
self.orb_atom_indices = np.cumsum([0] + [R.shape[0] for R in self.R_aii])
|
|
876
893
|
|
|
877
|
-
# def get_U_aii_gpaw(self, kpoint):
|
|
878
|
-
# """Phase corrected rotation matrices for the PAW projections."""
|
|
879
|
-
# return [ R_ii.T * np.exp( 2j * np.pi * np.dot(kpoiMax errnt, self.atom_map_T[a])) for a, R_ii in enumerate(self.R_aii)]
|
|
880
|
-
# # return [ R_ii.T for a, R_ii in enumerate(self.R_aii)] # no phase factor, try this
|
|
881
894
|
|
|
882
895
|
def set_gpaw(self, calculator):
|
|
883
896
|
"""Set all gpaw-related attributes."""
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from packaging.version import parse, Version
|
|
2
|
+
import gpaw
|
|
1
3
|
from pathlib import Path
|
|
2
4
|
import os
|
|
3
5
|
|
|
@@ -6,3 +8,14 @@ REF_DATA_PATH = Path(__file__).parents[0] / "ref_data"
|
|
|
6
8
|
TMP_DATA_PATH = Path(__file__).parents[0] / "tmp_data"
|
|
7
9
|
if not os.path.exists(TMP_DATA_PATH):
|
|
8
10
|
os.makedirs(TMP_DATA_PATH)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
if parse(gpaw.__version__) >= Version("26.0.0"):
|
|
14
|
+
GPAW_VERSION = 26
|
|
15
|
+
else:
|
|
16
|
+
GPAW_VERSION = 25
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
CALC_TYPE_LIST = ["OLD"]
|
|
20
|
+
if GPAW_VERSION == 26:
|
|
21
|
+
CALC_TYPE_LIST += ["NEW", "LEGACY"]
|