valyte 0.1.8__tar.gz → 0.1.11__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.
- {valyte-0.1.8/valyte.egg-info → valyte-0.1.11}/PKG-INFO +72 -2
- {valyte-0.1.8 → valyte-0.1.11}/README.md +71 -1
- valyte-0.1.11/pyproject.toml +3 -0
- {valyte-0.1.8 → valyte-0.1.11}/setup.py +1 -1
- valyte-0.1.11/valyte/band.py +247 -0
- valyte-0.1.11/valyte/band_plot.py +86 -0
- {valyte-0.1.8 → valyte-0.1.11}/valyte/cli.py +81 -78
- valyte-0.1.11/valyte/dos_plot.py +380 -0
- valyte-0.1.11/valyte/ipr.py +186 -0
- valyte-0.1.11/valyte/kpoints.py +80 -0
- valyte-0.1.11/valyte/potcar.py +36 -0
- valyte-0.1.11/valyte/supercell.py +18 -0
- {valyte-0.1.8 → valyte-0.1.11/valyte.egg-info}/PKG-INFO +72 -2
- {valyte-0.1.8 → valyte-0.1.11}/valyte.egg-info/SOURCES.txt +3 -0
- valyte-0.1.8/valyte/band.py +0 -278
- valyte-0.1.8/valyte/band_plot.py +0 -127
- valyte-0.1.8/valyte/dos_plot.py +0 -549
- valyte-0.1.8/valyte/kpoints.py +0 -96
- valyte-0.1.8/valyte/supercell.py +0 -35
- {valyte-0.1.8 → valyte-0.1.11}/MANIFEST.in +0 -0
- {valyte-0.1.8 → valyte-0.1.11}/setup.cfg +0 -0
- {valyte-0.1.8 → valyte-0.1.11}/valyte/Logo.png +0 -0
- {valyte-0.1.8 → valyte-0.1.11}/valyte/__init__.py +0 -0
- {valyte-0.1.8 → valyte-0.1.11}/valyte/data/__init__.py +0 -0
- {valyte-0.1.8 → valyte-0.1.11}/valyte/data/bradcrack.json +0 -0
- {valyte-0.1.8 → valyte-0.1.11}/valyte/valyte_band.png +0 -0
- {valyte-0.1.8 → valyte-0.1.11}/valyte/valyte_dos.png +0 -0
- {valyte-0.1.8 → valyte-0.1.11}/valyte.egg-info/dependency_links.txt +0 -0
- {valyte-0.1.8 → valyte-0.1.11}/valyte.egg-info/entry_points.txt +0 -0
- {valyte-0.1.8 → valyte-0.1.11}/valyte.egg-info/requires.txt +0 -0
- {valyte-0.1.8 → valyte-0.1.11}/valyte.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: valyte
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.11
|
|
4
4
|
Summary: A comprehensive CLI tool for VASP pre-processing (Supercells, K-points) and post-processing (DOS, Band Structure plotting)
|
|
5
5
|
Home-page: https://github.com/nikyadav002/Valyte-Project
|
|
6
6
|
Author: Nikhil
|
|
@@ -42,6 +42,7 @@ Requires-Dist: seekpath
|
|
|
42
42
|
- VBM alignment to 0 eV.
|
|
43
43
|
- Color-coded bands (Purple for VB, Teal for CB).
|
|
44
44
|
- High-symmetry path labels from KPOINTS.
|
|
45
|
+
- **IPR Analysis**: Compute Inverse Participation Ratio from PROCAR to analyze wavefunction localization.
|
|
45
46
|
- **Publication Quality**: Clean aesthetics, custom fonts (Arial, Helvetica, Times New Roman), high DPI output.
|
|
46
47
|
|
|
47
48
|
## Installation
|
|
@@ -113,6 +114,9 @@ valyte supercell 3 3 1 -i POSCAR_primitive -o POSCAR_3x3x1
|
|
|
113
114
|
|
|
114
115
|
Automatically generate a KPOINTS file with high-symmetry paths for band structure calculations.
|
|
115
116
|
|
|
117
|
+
> [!TIP]
|
|
118
|
+
> **Smart K-Path Generation (New in v0.1.7+)**: Valyte now automatically determines the standard path (e.g., `\Gamma - Y - V` for Monoclinic cells) using the **Bradley-Cracknell** convention by default. This ensures clean, publication-ready labels without external dependencies.
|
|
119
|
+
|
|
116
120
|
```bash
|
|
117
121
|
valyte band kpt-gen [options]
|
|
118
122
|
```
|
|
@@ -121,12 +125,20 @@ valyte band kpt-gen [options]
|
|
|
121
125
|
- `-i`, `--input`: Input POSCAR file (default: `POSCAR`).
|
|
122
126
|
- `-n`, `--npoints`: Points per segment (default: `40`).
|
|
123
127
|
- `-o`, `--output`: Output filename (default: `KPOINTS`).
|
|
128
|
+
- `--mode`: Path convention. Options: `bradcrack` (Default), `seekpath`, `latimer_munro`, `setyawan_curtarolo`.
|
|
124
129
|
|
|
125
130
|
**Example:**
|
|
126
131
|
```bash
|
|
127
|
-
|
|
132
|
+
# Default (Smart/BradCrack)
|
|
133
|
+
valyte band kpt-gen -n 60
|
|
134
|
+
|
|
135
|
+
# Explicitly use Seekpath convention
|
|
136
|
+
valyte band kpt-gen --mode seekpath
|
|
128
137
|
```
|
|
129
138
|
|
|
139
|
+
> [!IMPORTANT]
|
|
140
|
+
> The command will generate a **`POSCAR_standard`** file. You **MUST** use this structure for your band structure calculation (i.e., `cp POSCAR_standard POSCAR`) because the K-path corresponds to this specific orientation. Using your original POSCAR may result in incorrect paths.
|
|
141
|
+
|
|
130
142
|
### 🕸️ Generate K-Points (Interactive)
|
|
131
143
|
|
|
132
144
|
Generate a `KPOINTS` file for SCF calculations interactively.
|
|
@@ -141,6 +153,38 @@ This command will prompt you for:
|
|
|
141
153
|
|
|
142
154
|
It automatically calculates the optimal grid based on your `POSCAR` structure.
|
|
143
155
|
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### 🧪 Generate POTCAR
|
|
159
|
+
|
|
160
|
+
Generate a `POTCAR` file based on the species in your `POSCAR`.
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
valyte potcar [options]
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
**Options:**
|
|
167
|
+
- `-i`, `--input`: Input POSCAR file (default: `POSCAR`).
|
|
168
|
+
- `-o`, `--output`: Output filename (default: `POTCAR`).
|
|
169
|
+
- `--functional`: Functional to use (default: `PBE`). Options include `PBE`, `PBE_52`, `PBE_54`, `LDA`, etc.
|
|
170
|
+
|
|
171
|
+
**Example:**
|
|
172
|
+
```bash
|
|
173
|
+
# Generate POTCAR using default PBE functional
|
|
174
|
+
valyte potcar
|
|
175
|
+
|
|
176
|
+
# Use a specific functional
|
|
177
|
+
valyte potcar --functional PBE_54
|
|
178
|
+
|
|
179
|
+
# Specify input and output files
|
|
180
|
+
valyte potcar -i POSCAR_relaxed -o POTCAR_new
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
> [!IMPORTANT]
|
|
184
|
+
> **Pymatgen Configuration Required**: This command requires Pymatgen to be configured with your VASP pseudopotential directory. Set `PMG_VASP_PSP_DIR` in your `~/.pmgrc.yaml` file. See the [Pymatgen documentation](https://pymatgen.org/installation.html#potcar-setup) for setup instructions.
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
144
188
|
#### 2. Plot Band Structure
|
|
145
189
|
|
|
146
190
|
Plot the electronic band structure from `vasprun.xml`.
|
|
@@ -205,4 +249,30 @@ valyte dos -e Fe "Fe(d)"
|
|
|
205
249
|
valyte dos ./vasp_data --xlim -5 5 -o my_dos.png
|
|
206
250
|
```
|
|
207
251
|
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
### 📐 Compute IPR (Inverse Participation Ratio)
|
|
255
|
+
|
|
256
|
+
Compute the Inverse Participation Ratio (IPR) from VASP `PROCAR` to analyze wavefunction localization.
|
|
257
|
+
|
|
258
|
+
```bash
|
|
259
|
+
valyte ipr
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
This interactive command will:
|
|
263
|
+
1. Read the `PROCAR` file from the current directory.
|
|
264
|
+
2. Display the number of k-points, bands, and atoms.
|
|
265
|
+
3. Prompt you for **band indices** to analyze (e.g., `5 6 7` or `5-7`).
|
|
266
|
+
4. Optionally show per-k-point IPR values.
|
|
267
|
+
5. Save results to `ipr_procar.dat`.
|
|
268
|
+
|
|
269
|
+
**Output Columns:**
|
|
270
|
+
- **Band**: Band index.
|
|
271
|
+
- **Energy**: Average energy (eV) across k-points.
|
|
272
|
+
- **IPR**: Inverse Participation Ratio (higher = more localized).
|
|
273
|
+
- **N_eff**: Effective number of atoms (1/IPR).
|
|
274
|
+
|
|
275
|
+
> [!TIP]
|
|
276
|
+
> Use IPR to identify localized defect states. A state localized on a single atom has IPR ≈ 1.0 and N_eff ≈ 1. Delocalized band states have small IPR and large N_eff.
|
|
277
|
+
|
|
208
278
|
</details>
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
- VBM alignment to 0 eV.
|
|
24
24
|
- Color-coded bands (Purple for VB, Teal for CB).
|
|
25
25
|
- High-symmetry path labels from KPOINTS.
|
|
26
|
+
- **IPR Analysis**: Compute Inverse Participation Ratio from PROCAR to analyze wavefunction localization.
|
|
26
27
|
- **Publication Quality**: Clean aesthetics, custom fonts (Arial, Helvetica, Times New Roman), high DPI output.
|
|
27
28
|
|
|
28
29
|
## Installation
|
|
@@ -94,6 +95,9 @@ valyte supercell 3 3 1 -i POSCAR_primitive -o POSCAR_3x3x1
|
|
|
94
95
|
|
|
95
96
|
Automatically generate a KPOINTS file with high-symmetry paths for band structure calculations.
|
|
96
97
|
|
|
98
|
+
> [!TIP]
|
|
99
|
+
> **Smart K-Path Generation (New in v0.1.7+)**: Valyte now automatically determines the standard path (e.g., `\Gamma - Y - V` for Monoclinic cells) using the **Bradley-Cracknell** convention by default. This ensures clean, publication-ready labels without external dependencies.
|
|
100
|
+
|
|
97
101
|
```bash
|
|
98
102
|
valyte band kpt-gen [options]
|
|
99
103
|
```
|
|
@@ -102,12 +106,20 @@ valyte band kpt-gen [options]
|
|
|
102
106
|
- `-i`, `--input`: Input POSCAR file (default: `POSCAR`).
|
|
103
107
|
- `-n`, `--npoints`: Points per segment (default: `40`).
|
|
104
108
|
- `-o`, `--output`: Output filename (default: `KPOINTS`).
|
|
109
|
+
- `--mode`: Path convention. Options: `bradcrack` (Default), `seekpath`, `latimer_munro`, `setyawan_curtarolo`.
|
|
105
110
|
|
|
106
111
|
**Example:**
|
|
107
112
|
```bash
|
|
108
|
-
|
|
113
|
+
# Default (Smart/BradCrack)
|
|
114
|
+
valyte band kpt-gen -n 60
|
|
115
|
+
|
|
116
|
+
# Explicitly use Seekpath convention
|
|
117
|
+
valyte band kpt-gen --mode seekpath
|
|
109
118
|
```
|
|
110
119
|
|
|
120
|
+
> [!IMPORTANT]
|
|
121
|
+
> The command will generate a **`POSCAR_standard`** file. You **MUST** use this structure for your band structure calculation (i.e., `cp POSCAR_standard POSCAR`) because the K-path corresponds to this specific orientation. Using your original POSCAR may result in incorrect paths.
|
|
122
|
+
|
|
111
123
|
### 🕸️ Generate K-Points (Interactive)
|
|
112
124
|
|
|
113
125
|
Generate a `KPOINTS` file for SCF calculations interactively.
|
|
@@ -122,6 +134,38 @@ This command will prompt you for:
|
|
|
122
134
|
|
|
123
135
|
It automatically calculates the optimal grid based on your `POSCAR` structure.
|
|
124
136
|
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
### 🧪 Generate POTCAR
|
|
140
|
+
|
|
141
|
+
Generate a `POTCAR` file based on the species in your `POSCAR`.
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
valyte potcar [options]
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Options:**
|
|
148
|
+
- `-i`, `--input`: Input POSCAR file (default: `POSCAR`).
|
|
149
|
+
- `-o`, `--output`: Output filename (default: `POTCAR`).
|
|
150
|
+
- `--functional`: Functional to use (default: `PBE`). Options include `PBE`, `PBE_52`, `PBE_54`, `LDA`, etc.
|
|
151
|
+
|
|
152
|
+
**Example:**
|
|
153
|
+
```bash
|
|
154
|
+
# Generate POTCAR using default PBE functional
|
|
155
|
+
valyte potcar
|
|
156
|
+
|
|
157
|
+
# Use a specific functional
|
|
158
|
+
valyte potcar --functional PBE_54
|
|
159
|
+
|
|
160
|
+
# Specify input and output files
|
|
161
|
+
valyte potcar -i POSCAR_relaxed -o POTCAR_new
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
> [!IMPORTANT]
|
|
165
|
+
> **Pymatgen Configuration Required**: This command requires Pymatgen to be configured with your VASP pseudopotential directory. Set `PMG_VASP_PSP_DIR` in your `~/.pmgrc.yaml` file. See the [Pymatgen documentation](https://pymatgen.org/installation.html#potcar-setup) for setup instructions.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
125
169
|
#### 2. Plot Band Structure
|
|
126
170
|
|
|
127
171
|
Plot the electronic band structure from `vasprun.xml`.
|
|
@@ -186,4 +230,30 @@ valyte dos -e Fe "Fe(d)"
|
|
|
186
230
|
valyte dos ./vasp_data --xlim -5 5 -o my_dos.png
|
|
187
231
|
```
|
|
188
232
|
|
|
233
|
+
---
|
|
234
|
+
|
|
235
|
+
### 📐 Compute IPR (Inverse Participation Ratio)
|
|
236
|
+
|
|
237
|
+
Compute the Inverse Participation Ratio (IPR) from VASP `PROCAR` to analyze wavefunction localization.
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
valyte ipr
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
This interactive command will:
|
|
244
|
+
1. Read the `PROCAR` file from the current directory.
|
|
245
|
+
2. Display the number of k-points, bands, and atoms.
|
|
246
|
+
3. Prompt you for **band indices** to analyze (e.g., `5 6 7` or `5-7`).
|
|
247
|
+
4. Optionally show per-k-point IPR values.
|
|
248
|
+
5. Save results to `ipr_procar.dat`.
|
|
249
|
+
|
|
250
|
+
**Output Columns:**
|
|
251
|
+
- **Band**: Band index.
|
|
252
|
+
- **Energy**: Average energy (eV) across k-points.
|
|
253
|
+
- **IPR**: Inverse Participation Ratio (higher = more localized).
|
|
254
|
+
- **N_eff**: Effective number of atoms (1/IPR).
|
|
255
|
+
|
|
256
|
+
> [!TIP]
|
|
257
|
+
> Use IPR to identify localized defect states. A state localized on a single atom has IPR ≈ 1.0 and N_eff ≈ 1. Delocalized band states have small IPR and large N_eff.
|
|
258
|
+
|
|
189
259
|
</details>
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
"""Band structure KPOINTS generation."""
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import json
|
|
5
|
+
import numpy as np
|
|
6
|
+
import seekpath
|
|
7
|
+
from pymatgen.core import Structure
|
|
8
|
+
from pymatgen.symmetry.bandstructure import HighSymmKpath
|
|
9
|
+
from pymatgen.symmetry.analyzer import SpacegroupAnalyzer
|
|
10
|
+
try:
|
|
11
|
+
from importlib.resources import files as ilr_files
|
|
12
|
+
except ImportError:
|
|
13
|
+
from importlib_resources import files as ilr_files
|
|
14
|
+
|
|
15
|
+
from valyte.potcar import generate_potcar
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def generate_band_kpoints(poscar_path="POSCAR", npoints=40, output="KPOINTS", symprec=0.01, mode="bradcrack"):
|
|
19
|
+
"""Generate a line-mode KPOINTS file for band structure calculations."""
|
|
20
|
+
|
|
21
|
+
if not os.path.exists(poscar_path):
|
|
22
|
+
raise FileNotFoundError(f"{poscar_path} not found")
|
|
23
|
+
|
|
24
|
+
mode = (mode or "bradcrack").lower()
|
|
25
|
+
|
|
26
|
+
structure = Structure.from_file(poscar_path)
|
|
27
|
+
|
|
28
|
+
if mode == "bradcrack":
|
|
29
|
+
try:
|
|
30
|
+
kpath = BradCrackKpath(structure, symprec=symprec)
|
|
31
|
+
prim_std = kpath.prim
|
|
32
|
+
path = kpath.path
|
|
33
|
+
kpoints = kpath.kpoints
|
|
34
|
+
|
|
35
|
+
standard_filename = "POSCAR_standard"
|
|
36
|
+
prim_std.to(filename=standard_filename)
|
|
37
|
+
except Exception as e:
|
|
38
|
+
raise RuntimeError(f"Error generating Bradley-Cracknell path: {e}")
|
|
39
|
+
else:
|
|
40
|
+
try:
|
|
41
|
+
if mode == "seekpath":
|
|
42
|
+
mode = "hinuma"
|
|
43
|
+
|
|
44
|
+
sga = SpacegroupAnalyzer(structure, symprec=symprec)
|
|
45
|
+
prim_std = sga.get_primitive_standard_structure()
|
|
46
|
+
except Exception as e:
|
|
47
|
+
raise RuntimeError(f"Error during standardization: {e}")
|
|
48
|
+
|
|
49
|
+
try:
|
|
50
|
+
kpath = HighSymmKpath(prim_std, path_type=mode, symprec=symprec)
|
|
51
|
+
|
|
52
|
+
standard_filename = "POSCAR_standard"
|
|
53
|
+
prim_std.to(filename=standard_filename)
|
|
54
|
+
|
|
55
|
+
path = kpath.kpath["path"]
|
|
56
|
+
kpoints = kpath.kpath["kpoints"]
|
|
57
|
+
except Exception as e:
|
|
58
|
+
raise RuntimeError(f"Error generating K-path: {e}")
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
with open(output, "w") as f:
|
|
62
|
+
f.write("KPOINTS for Band Structure\n")
|
|
63
|
+
f.write(f"{npoints}\n")
|
|
64
|
+
f.write("Line-mode\n")
|
|
65
|
+
f.write("Reciprocal\n")
|
|
66
|
+
|
|
67
|
+
for subpath in path:
|
|
68
|
+
for i in range(len(subpath) - 1):
|
|
69
|
+
start_label = subpath[i]
|
|
70
|
+
end_label = subpath[i + 1]
|
|
71
|
+
|
|
72
|
+
start_coords = kpoints[start_label]
|
|
73
|
+
end_coords = kpoints[end_label]
|
|
74
|
+
|
|
75
|
+
f.write(
|
|
76
|
+
f"{start_coords[0]:10.6f} {start_coords[1]:10.6f} {start_coords[2]:10.6f} ! {start_label}\n"
|
|
77
|
+
)
|
|
78
|
+
f.write(
|
|
79
|
+
f"{end_coords[0]:10.6f} {end_coords[1]:10.6f} {end_coords[2]:10.6f} ! {end_label}\n"
|
|
80
|
+
)
|
|
81
|
+
f.write("\n")
|
|
82
|
+
|
|
83
|
+
print(f"Generated {output} ({' - '.join([' - '.join(seg) for seg in path])})")
|
|
84
|
+
print(f"Generated {standard_filename} (Standardized Primitive Cell)")
|
|
85
|
+
print("IMPORTANT: Use POSCAR_standard for the band calculation.")
|
|
86
|
+
except Exception as e:
|
|
87
|
+
raise RuntimeError(f"Error writing KPOINTS file: {e}")
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
print("Generating default POTCAR (PBE)...")
|
|
91
|
+
generate_potcar(poscar_path=poscar_path, functional="PBE", output="POTCAR")
|
|
92
|
+
except Exception as e:
|
|
93
|
+
print(f"Warning: could not generate POTCAR: {e}")
|
|
94
|
+
print("Proceeding without POTCAR generation.")
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class BradCrackKpath:
|
|
98
|
+
"""Bradley-Cracknell K-path generation using SeeK-path output."""
|
|
99
|
+
|
|
100
|
+
def __init__(self, structure, symprec=0.01):
|
|
101
|
+
self.structure = structure
|
|
102
|
+
self.symprec = symprec
|
|
103
|
+
|
|
104
|
+
sga = SpacegroupAnalyzer(structure, symprec=symprec)
|
|
105
|
+
self._spg_data = sga.get_symmetry_dataset()
|
|
106
|
+
|
|
107
|
+
cell = (
|
|
108
|
+
structure.lattice.matrix,
|
|
109
|
+
structure.frac_coords,
|
|
110
|
+
[s.specie.number for s in structure],
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
self._seek_data = seekpath.get_path(cell, symprec=symprec)
|
|
114
|
+
|
|
115
|
+
prim_lattice = self._seek_data["primitive_lattice"]
|
|
116
|
+
prim_pos = self._seek_data["primitive_positions"]
|
|
117
|
+
prim_types = self._seek_data["primitive_types"]
|
|
118
|
+
|
|
119
|
+
z_to_specie = {s.specie.number: s.specie for s in structure}
|
|
120
|
+
prim_species = [z_to_specie[z] for z in prim_types]
|
|
121
|
+
|
|
122
|
+
self.prim = Structure(prim_lattice, prim_species, prim_pos)
|
|
123
|
+
|
|
124
|
+
conv_lattice = self._seek_data["conv_lattice"]
|
|
125
|
+
conv_pos = self._seek_data["conv_positions"]
|
|
126
|
+
conv_types = self._seek_data["conv_types"]
|
|
127
|
+
conv_species = [z_to_specie[z] for z in conv_types]
|
|
128
|
+
self.conv = Structure(conv_lattice, conv_species, conv_pos)
|
|
129
|
+
|
|
130
|
+
self._get_bradcrack_path()
|
|
131
|
+
|
|
132
|
+
def _get_bradcrack_path(self):
|
|
133
|
+
a, b, c = self.conv.lattice.abc
|
|
134
|
+
angles = self.conv.lattice.angles
|
|
135
|
+
|
|
136
|
+
angles_r = [round(x, 3) for x in angles]
|
|
137
|
+
unique_val = min(angles_r, key=angles_r.count)
|
|
138
|
+
unique = angles_r.index(unique_val)
|
|
139
|
+
|
|
140
|
+
spg_symbol = self._spg_data["international"]
|
|
141
|
+
spg_number = self._spg_data["number"]
|
|
142
|
+
|
|
143
|
+
lattice_type = self.get_lattice_type(spg_number)
|
|
144
|
+
bravais = self._get_bravais_lattice(spg_symbol, lattice_type, a, b, c, unique)
|
|
145
|
+
|
|
146
|
+
json_file = ilr_files("valyte.data").joinpath("bradcrack.json")
|
|
147
|
+
with json_file.open("r") as f:
|
|
148
|
+
data = json.load(f)
|
|
149
|
+
|
|
150
|
+
if bravais not in data:
|
|
151
|
+
raise ValueError(f"Bravais lattice code '{bravais}' not found in BradCrack data.")
|
|
152
|
+
|
|
153
|
+
self.bradcrack_data = data[bravais]
|
|
154
|
+
self.kpoints = self.bradcrack_data["kpoints"]
|
|
155
|
+
self.path = self.bradcrack_data["path"]
|
|
156
|
+
|
|
157
|
+
def get_lattice_type(self, number):
|
|
158
|
+
if 1 <= number <= 2:
|
|
159
|
+
return "triclinic"
|
|
160
|
+
if 3 <= number <= 15:
|
|
161
|
+
return "monoclinic"
|
|
162
|
+
if 16 <= number <= 74:
|
|
163
|
+
return "orthorhombic"
|
|
164
|
+
if 75 <= number <= 142:
|
|
165
|
+
return "tetragonal"
|
|
166
|
+
if 143 <= number <= 167:
|
|
167
|
+
if number in [146, 148, 155, 160, 161, 166, 167]:
|
|
168
|
+
return "rhombohedral"
|
|
169
|
+
return "trigonal"
|
|
170
|
+
if 168 <= number <= 194:
|
|
171
|
+
return "hexagonal"
|
|
172
|
+
if 195 <= number <= 230:
|
|
173
|
+
return "cubic"
|
|
174
|
+
return "unknown"
|
|
175
|
+
|
|
176
|
+
def _get_bravais_lattice(self, spg_symbol, lattice_type, a, b, c, unique):
|
|
177
|
+
if lattice_type == "triclinic":
|
|
178
|
+
return "triclinic"
|
|
179
|
+
|
|
180
|
+
if lattice_type == "monoclinic":
|
|
181
|
+
if "P" in spg_symbol:
|
|
182
|
+
if unique == 0:
|
|
183
|
+
return "mon_p_a"
|
|
184
|
+
if unique == 1:
|
|
185
|
+
return "mon_p_b"
|
|
186
|
+
if unique == 2:
|
|
187
|
+
return "mon_p_c"
|
|
188
|
+
if "C" in spg_symbol:
|
|
189
|
+
if unique == 0:
|
|
190
|
+
return "mon_c_a"
|
|
191
|
+
if unique == 1:
|
|
192
|
+
return "mon_c_b"
|
|
193
|
+
if unique == 2:
|
|
194
|
+
return "mon_c_c"
|
|
195
|
+
|
|
196
|
+
if lattice_type == "orthorhombic":
|
|
197
|
+
if "P" in spg_symbol:
|
|
198
|
+
return "orth_p"
|
|
199
|
+
if "A" in spg_symbol or "C" in spg_symbol:
|
|
200
|
+
if a > b:
|
|
201
|
+
return "orth_c_a"
|
|
202
|
+
if b > a:
|
|
203
|
+
return "orth_c_b"
|
|
204
|
+
if "F" in spg_symbol:
|
|
205
|
+
inv_a2 = 1 / a**2
|
|
206
|
+
inv_b2 = 1 / b**2
|
|
207
|
+
inv_c2 = 1 / c**2
|
|
208
|
+
if (inv_a2 < inv_b2 + inv_c2) and (inv_b2 < inv_c2 + inv_a2) and (inv_c2 < inv_a2 + inv_b2):
|
|
209
|
+
return "orth_f_1"
|
|
210
|
+
if inv_c2 > inv_a2 + inv_b2:
|
|
211
|
+
return "orth_f_2"
|
|
212
|
+
if inv_b2 > inv_a2 + inv_c2:
|
|
213
|
+
return "orth_f_3"
|
|
214
|
+
if inv_a2 > inv_c2 + inv_b2:
|
|
215
|
+
return "orth_f_4"
|
|
216
|
+
if "I" in spg_symbol:
|
|
217
|
+
if a > b and a > c:
|
|
218
|
+
return "orth_i_a"
|
|
219
|
+
if b > a and b > c:
|
|
220
|
+
return "orth_i_b"
|
|
221
|
+
if c > a and c > b:
|
|
222
|
+
return "orth_i_c"
|
|
223
|
+
|
|
224
|
+
if lattice_type == "tetragonal":
|
|
225
|
+
if "P" in spg_symbol:
|
|
226
|
+
return "tet_p"
|
|
227
|
+
if "I" in spg_symbol:
|
|
228
|
+
return "tet_i_a" if a > c else "tet_i_c"
|
|
229
|
+
|
|
230
|
+
if lattice_type in ["trigonal", "hexagonal", "rhombohedral"]:
|
|
231
|
+
if "R" in spg_symbol:
|
|
232
|
+
return "trig_r_a" if a > np.sqrt(2) * c else "trig_r_c"
|
|
233
|
+
if "P" in spg_symbol:
|
|
234
|
+
if unique == 0:
|
|
235
|
+
return "trig_p_a"
|
|
236
|
+
if unique == 2:
|
|
237
|
+
return "trig_p_c"
|
|
238
|
+
|
|
239
|
+
if lattice_type == "cubic":
|
|
240
|
+
if "P" in spg_symbol:
|
|
241
|
+
return "cubic_p"
|
|
242
|
+
if "I" in spg_symbol:
|
|
243
|
+
return "cubic_i"
|
|
244
|
+
if "F" in spg_symbol:
|
|
245
|
+
return "cubic_f"
|
|
246
|
+
|
|
247
|
+
return "unknown"
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import numpy as np
|
|
3
|
+
import matplotlib as mpl
|
|
4
|
+
mpl.use("agg")
|
|
5
|
+
mpl.rcParams["axes.unicode_minus"] = False
|
|
6
|
+
import matplotlib.pyplot as plt
|
|
7
|
+
from pymatgen.io.vasp import BSVasprun
|
|
8
|
+
from pymatgen.electronic_structure.plotter import BSPlotter
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def plot_band_structure(vasprun_path, kpoints_path=None, output="valyte_band.png",
|
|
12
|
+
ylim=None, figsize=(4, 4), dpi=400, font="Arial"):
|
|
13
|
+
"""Plot the electronic band structure from a VASP vasprun.xml."""
|
|
14
|
+
|
|
15
|
+
if os.path.isdir(vasprun_path):
|
|
16
|
+
vasprun_path = os.path.join(vasprun_path, "vasprun.xml")
|
|
17
|
+
|
|
18
|
+
font_map = {
|
|
19
|
+
"arial": "Arial",
|
|
20
|
+
"helvetica": "Helvetica",
|
|
21
|
+
"times": "Times New Roman",
|
|
22
|
+
"times new roman": "Times New Roman",
|
|
23
|
+
}
|
|
24
|
+
font = font_map.get(font.lower(), "Arial")
|
|
25
|
+
mpl.rcParams["font.family"] = font
|
|
26
|
+
mpl.rcParams["axes.linewidth"] = 1.4
|
|
27
|
+
mpl.rcParams["font.weight"] = "bold"
|
|
28
|
+
mpl.rcParams["font.size"] = 14
|
|
29
|
+
mpl.rcParams["xtick.major.width"] = 1.2
|
|
30
|
+
mpl.rcParams["ytick.major.width"] = 1.2
|
|
31
|
+
|
|
32
|
+
try:
|
|
33
|
+
vr = BSVasprun(vasprun_path, parse_projected_eigen=False)
|
|
34
|
+
bs = vr.get_band_structure(kpoints_filename=kpoints_path, line_mode=True)
|
|
35
|
+
except Exception as e:
|
|
36
|
+
raise ValueError(f"Failed to load band structure: {e}")
|
|
37
|
+
|
|
38
|
+
bs_plotter = BSPlotter(bs)
|
|
39
|
+
data = bs_plotter.bs_plot_data(zero_to_efermi=True)
|
|
40
|
+
|
|
41
|
+
distances = data["distances"]
|
|
42
|
+
energies = data["energy"]
|
|
43
|
+
ticks = data["ticks"]
|
|
44
|
+
|
|
45
|
+
fig, ax = plt.subplots(figsize=figsize)
|
|
46
|
+
|
|
47
|
+
color_vb = "#8e44ad"
|
|
48
|
+
color_cb = "#2a9d8f"
|
|
49
|
+
|
|
50
|
+
for i in range(len(distances)):
|
|
51
|
+
d = distances[i]
|
|
52
|
+
|
|
53
|
+
if isinstance(energies, dict):
|
|
54
|
+
for spin in energies:
|
|
55
|
+
for band in energies[spin][i]:
|
|
56
|
+
c = color_vb if np.mean(band) <= 0 else color_cb
|
|
57
|
+
ax.plot(d, band, color=c, lw=1.5, alpha=1.0)
|
|
58
|
+
else:
|
|
59
|
+
for spin in energies[i]:
|
|
60
|
+
for band in energies[i][spin]:
|
|
61
|
+
c = color_vb if np.mean(band) <= 0 else color_cb
|
|
62
|
+
ax.plot(d, band, color=c, lw=1.5, alpha=1.0)
|
|
63
|
+
|
|
64
|
+
ax.set_xticks(ticks["distance"])
|
|
65
|
+
clean_labels = [(l or "").replace("$\\mid$", "|") for l in ticks["label"]]
|
|
66
|
+
ax.set_xticklabels(clean_labels, fontsize=14, fontweight="bold")
|
|
67
|
+
|
|
68
|
+
for d in ticks["distance"]:
|
|
69
|
+
ax.axvline(d, color="k", lw=0.8, ls="-", alpha=0.3)
|
|
70
|
+
|
|
71
|
+
ax.axhline(0, color="k", lw=0.8, ls="--", alpha=0.5)
|
|
72
|
+
|
|
73
|
+
ax.set_ylabel("Energy (eV)", fontsize=16, fontweight="bold", labelpad=8)
|
|
74
|
+
if ylim:
|
|
75
|
+
ax.set_ylim(ylim)
|
|
76
|
+
yticks = np.arange(np.ceil(ylim[0]), np.floor(ylim[1]) + 1, 1)
|
|
77
|
+
ax.set_yticks(yticks)
|
|
78
|
+
else:
|
|
79
|
+
ax.set_ylim(-4, 4)
|
|
80
|
+
ax.set_yticks(np.arange(-4, 5, 1))
|
|
81
|
+
|
|
82
|
+
ax.set_xlim(distances[0][0], distances[-1][-1])
|
|
83
|
+
|
|
84
|
+
plt.tight_layout()
|
|
85
|
+
plt.savefig(output, dpi=dpi)
|
|
86
|
+
plt.close(fig)
|