tools4vasp 0.0.2__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.
- tools4vasp-0.0.2/LICENSE +21 -0
- tools4vasp-0.0.2/PKG-INFO +63 -0
- tools4vasp-0.0.2/README.md +39 -0
- tools4vasp-0.0.2/pyproject.toml +32 -0
- tools4vasp-0.0.2/setup.cfg +4 -0
- tools4vasp-0.0.2/setup.py +29 -0
- tools4vasp-0.0.2/test/test_tools4vasp.py +3 -0
- tools4vasp-0.0.2/tools4vasp/__init__.py +0 -0
- tools4vasp-0.0.2/tools4vasp/add-MODECAR.py +13 -0
- tools4vasp-0.0.2/tools4vasp/chgcar2cube.py +111 -0
- tools4vasp-0.0.2/tools4vasp/elf2cube.py +112 -0
- tools4vasp-0.0.2/tools4vasp/freq2jmol.py +16 -0
- tools4vasp-0.0.2/tools4vasp/freq2mode.py +113 -0
- tools4vasp-0.0.2/tools4vasp/kgrid2kspacing.py +34 -0
- tools4vasp-0.0.2/tools4vasp/kspacing2kgrid.py +27 -0
- tools4vasp-0.0.2/tools4vasp/mixed_interpolate.py +145 -0
- tools4vasp-0.0.2/tools4vasp/neb2movie.py +73 -0
- tools4vasp-0.0.2/tools4vasp/plotIRC.py +161 -0
- tools4vasp-0.0.2/tools4vasp/plotNEB.py +141 -0
- tools4vasp-0.0.2/tools4vasp/poscar2nbands.py +21 -0
- tools4vasp-0.0.2/tools4vasp/split_vasp_freq.py +310 -0
- tools4vasp-0.0.2/tools4vasp/vasp2traj.py +44 -0
- tools4vasp-0.0.2/tools4vasp/vaspGetEF.py +178 -0
- tools4vasp-0.0.2/tools4vasp/vaspcheck.py +147 -0
- tools4vasp-0.0.2/tools4vasp/viewMode.py +61 -0
- tools4vasp-0.0.2/tools4vasp.egg-info/PKG-INFO +63 -0
- tools4vasp-0.0.2/tools4vasp.egg-info/SOURCES.txt +28 -0
- tools4vasp-0.0.2/tools4vasp.egg-info/dependency_links.txt +1 -0
- tools4vasp-0.0.2/tools4vasp.egg-info/requires.txt +5 -0
- tools4vasp-0.0.2/tools4vasp.egg-info/top_level.txt +1 -0
tools4vasp-0.0.2/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Patrick Melix
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: tools4vasp
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Python tools for VASP
|
|
5
|
+
Home-page: https://github.com/Tonner-Zech-Group/VASP-tools
|
|
6
|
+
Author: Patrick Melix
|
|
7
|
+
Author-email: Patrick Melix <patrick.melix@uni-leipzig.de>
|
|
8
|
+
Project-URL: Homepage, https://github.com/Tonner-Zech-Group/VASP-tools
|
|
9
|
+
Project-URL: Issues, https://github.com/Tonner-Zech-Group/VASP-tools/issues
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: Programming Language :: Unix Shell
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Operating System :: Unix
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Chemistry
|
|
16
|
+
Requires-Python: >=3.8
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
License-File: LICENSE
|
|
19
|
+
Requires-Dist: ase>=1.0
|
|
20
|
+
Requires-Dist: matplotlib>=3.8.4
|
|
21
|
+
Requires-Dist: natsort>=8.3.1
|
|
22
|
+
Requires-Dist: numpy>=1.24.3
|
|
23
|
+
Requires-Dist: pymatgen>=2023.5.10
|
|
24
|
+
|
|
25
|
+
# VASP-tools
|
|
26
|
+
|
|
27
|
+
Our collection of tools for pre- and post-processing VASP calculations. Mainly Python and Bash.
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
Clone this repository and run `pip install .` inside the main directory. If you want to always use the latest content of the repo you can use the 'developement' install of pip by running `pip install -e .`. Just doing `git pull` to get the latest content of the repo will then automatically result in the usage of the latest code without need to reinstall.
|
|
32
|
+
|
|
33
|
+
You can also use the latest release by installing it from PyPi:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install orcatools
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Dependencies
|
|
40
|
+
|
|
41
|
+
Different for each script, but mainly
|
|
42
|
+
|
|
43
|
+
- [ASE](https://wiki.fysik.dtu.dk/ase/)
|
|
44
|
+
- [VTST](http://theory.cm.utexas.edu/vtsttools/)
|
|
45
|
+
- [Pymatgen](https://pymatgen.org/)
|
|
46
|
+
- [Geodesic Interpolation](https://github.com/virtualzx-nad/geodesic-interpolate)
|
|
47
|
+
|
|
48
|
+
## Pre-Processing
|
|
49
|
+
|
|
50
|
+
- freq2mode: generates MODECAR and mass-weighted MODCAR files from frequency calculations
|
|
51
|
+
|
|
52
|
+
## Post-Processing
|
|
53
|
+
|
|
54
|
+
- chgcar2cube.py: Convert CHGCAR-like files to cube files using Pymatgen and ASE.
|
|
55
|
+
- neb2movie.py: Convert VASP NEB to ASE ext-xyz movie, just like nebmovie.pl of VTST.
|
|
56
|
+
- poscar2nbands.py: Helper to get the NBANDS value for LOBSTER calculations using the current POSCAR, INCAR and POTCAR setup with 'standard' options.
|
|
57
|
+
- vasp2traj.py: Convert VASP geometry optimization output to ASE compatible ext-xyz trajectory file.
|
|
58
|
+
- vasp-check.py: Assert proper occupations and SCF+GO convergence in VASP using ASE.
|
|
59
|
+
- vaspGetEF.py: Creates a plot of energy and forces along multiple GO runs (e.g. for restart jobs). Gathers data in all numeric subfolders and this folder containing a vasprun.xml file (depth one) and combines them in a single plot.
|
|
60
|
+
- visualize-magnetization.sh: Creates a VMD visualisation state file for the magnetization denisty by splitting the CHGCAR (by running chgsplit.pl), converting it to a cube file (by running chgcar2cube.sh) and then creating representations for VMD.
|
|
61
|
+
- viewMode.py: Shows a graphical preview of a MODECAR file using ase gui
|
|
62
|
+
- plotIRC: Tool that creates a plot of VASP IRC calculations in both direction and is compatible with shifts in the starting structure.
|
|
63
|
+
- replace_potcar_symlinks.sh: Searches for POTCARS in subdirs and replaces them with symlinks. CAREFUL!
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# VASP-tools
|
|
2
|
+
|
|
3
|
+
Our collection of tools for pre- and post-processing VASP calculations. Mainly Python and Bash.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Clone this repository and run `pip install .` inside the main directory. If you want to always use the latest content of the repo you can use the 'developement' install of pip by running `pip install -e .`. Just doing `git pull` to get the latest content of the repo will then automatically result in the usage of the latest code without need to reinstall.
|
|
8
|
+
|
|
9
|
+
You can also use the latest release by installing it from PyPi:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install orcatools
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Dependencies
|
|
16
|
+
|
|
17
|
+
Different for each script, but mainly
|
|
18
|
+
|
|
19
|
+
- [ASE](https://wiki.fysik.dtu.dk/ase/)
|
|
20
|
+
- [VTST](http://theory.cm.utexas.edu/vtsttools/)
|
|
21
|
+
- [Pymatgen](https://pymatgen.org/)
|
|
22
|
+
- [Geodesic Interpolation](https://github.com/virtualzx-nad/geodesic-interpolate)
|
|
23
|
+
|
|
24
|
+
## Pre-Processing
|
|
25
|
+
|
|
26
|
+
- freq2mode: generates MODECAR and mass-weighted MODCAR files from frequency calculations
|
|
27
|
+
|
|
28
|
+
## Post-Processing
|
|
29
|
+
|
|
30
|
+
- chgcar2cube.py: Convert CHGCAR-like files to cube files using Pymatgen and ASE.
|
|
31
|
+
- neb2movie.py: Convert VASP NEB to ASE ext-xyz movie, just like nebmovie.pl of VTST.
|
|
32
|
+
- poscar2nbands.py: Helper to get the NBANDS value for LOBSTER calculations using the current POSCAR, INCAR and POTCAR setup with 'standard' options.
|
|
33
|
+
- vasp2traj.py: Convert VASP geometry optimization output to ASE compatible ext-xyz trajectory file.
|
|
34
|
+
- vasp-check.py: Assert proper occupations and SCF+GO convergence in VASP using ASE.
|
|
35
|
+
- vaspGetEF.py: Creates a plot of energy and forces along multiple GO runs (e.g. for restart jobs). Gathers data in all numeric subfolders and this folder containing a vasprun.xml file (depth one) and combines them in a single plot.
|
|
36
|
+
- visualize-magnetization.sh: Creates a VMD visualisation state file for the magnetization denisty by splitting the CHGCAR (by running chgsplit.pl), converting it to a cube file (by running chgcar2cube.sh) and then creating representations for VMD.
|
|
37
|
+
- viewMode.py: Shows a graphical preview of a MODECAR file using ase gui
|
|
38
|
+
- plotIRC: Tool that creates a plot of VASP IRC calculations in both direction and is compatible with shifts in the starting structure.
|
|
39
|
+
- replace_potcar_symlinks.sh: Searches for POTCARS in subdirs and replaces them with symlinks. CAREFUL!
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "tools4vasp"
|
|
7
|
+
dependencies = [
|
|
8
|
+
'ase >= 1.0',
|
|
9
|
+
'matplotlib >= 3.8.4',
|
|
10
|
+
'natsort >= 8.3.1',
|
|
11
|
+
'numpy >= 1.24.3',
|
|
12
|
+
'pymatgen >= 2023.5.10',
|
|
13
|
+
]
|
|
14
|
+
version = "0.0.2"
|
|
15
|
+
authors = [
|
|
16
|
+
{ name="Patrick Melix", email="patrick.melix@uni-leipzig.de" },
|
|
17
|
+
]
|
|
18
|
+
description = "Python tools for VASP"
|
|
19
|
+
readme = "README.md"
|
|
20
|
+
requires-python = ">=3.8"
|
|
21
|
+
classifiers = [
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Unix Shell",
|
|
24
|
+
"License :: OSI Approved :: MIT License",
|
|
25
|
+
"Operating System :: Unix",
|
|
26
|
+
"Intended Audience :: Science/Research",
|
|
27
|
+
"Topic :: Scientific/Engineering :: Chemistry",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.urls]
|
|
31
|
+
Homepage = "https://github.com/Tonner-Zech-Group/VASP-tools"
|
|
32
|
+
Issues = "https://github.com/Tonner-Zech-Group/VASP-tools/issues"
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from setuptools import setup
|
|
2
|
+
import glob
|
|
3
|
+
import site
|
|
4
|
+
import sys
|
|
5
|
+
site.ENABLE_USER_SITE = "--user" in sys.argv[1:]
|
|
6
|
+
|
|
7
|
+
with open("README.md", 'r') as f:
|
|
8
|
+
long_description = f.read()
|
|
9
|
+
|
|
10
|
+
scripts = []
|
|
11
|
+
for file in glob.glob('tools4vasp/*'):
|
|
12
|
+
if file.endswith('.py'):
|
|
13
|
+
scripts.append(file)
|
|
14
|
+
elif file.endswith('.sh'):
|
|
15
|
+
scripts.append(file)
|
|
16
|
+
|
|
17
|
+
setup(
|
|
18
|
+
name='tools4vasp',
|
|
19
|
+
version='1.0',
|
|
20
|
+
description='Python tools for VASP',
|
|
21
|
+
long_description=open('README.md').read(),
|
|
22
|
+
long_description_content_type='text/markdown',
|
|
23
|
+
author='Patrick Melix',
|
|
24
|
+
author_email='patrick.melix@uni-leipzig.de',
|
|
25
|
+
url="https://github.com/Tonner-Zech-Group/VASP-tools",
|
|
26
|
+
packages=['tools4vasp'],
|
|
27
|
+
install_requires=['ase', 'numpy', 'matplotlib', 'natsort', 'pymatgen'],
|
|
28
|
+
console_scripts = scripts
|
|
29
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
# Script to convert CHGCAR files to cube files and convert to e-/Ang^3
|
|
4
|
+
# by Patrick Melix
|
|
5
|
+
# 2022/04/04
|
|
6
|
+
#
|
|
7
|
+
# You can import the module and then call .main() or use it as a script
|
|
8
|
+
from pymatgen.io.vasp.outputs import Chgcar
|
|
9
|
+
from pymatgen.io.ase import AseAtomsAdaptor
|
|
10
|
+
from ase.io.cube import write_cube
|
|
11
|
+
import numpy as np
|
|
12
|
+
import os
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main(inFiles, outFiles, verbose=True, return_integrals=False, return_spin_integrals=False, mult_volume=False):
|
|
16
|
+
assert len(inFiles) == len(outFiles), "Number of input and output files must be equal!"
|
|
17
|
+
integrals = []
|
|
18
|
+
spin_integrals = []
|
|
19
|
+
for iFile,inFile in enumerate(inFiles):
|
|
20
|
+
if not os.path.isfile(inFile):
|
|
21
|
+
raise ValueError('File {:} does not exist'.format(inFile))
|
|
22
|
+
|
|
23
|
+
#if output exists mv to .bak
|
|
24
|
+
if os.path.isfile(outFiles[iFile]):
|
|
25
|
+
if verbose:
|
|
26
|
+
print('ATTENTION: {:} exists, moving to *.bak'.format(outFiles[iFile]))
|
|
27
|
+
os.rename(outFiles[iFile], outFiles[iFile]+'.bak')
|
|
28
|
+
|
|
29
|
+
if verbose:
|
|
30
|
+
print("Reading {}".format(inFile))
|
|
31
|
+
full_chgcar = Chgcar.from_file(inFile)
|
|
32
|
+
spinpol = 'diff' in full_chgcar.data.keys()
|
|
33
|
+
if return_spin_integrals and not spinpol:
|
|
34
|
+
raise ValueError("File {} is not spinpolarized!".format(inFile))
|
|
35
|
+
shape = full_chgcar.data['total'].shape
|
|
36
|
+
n_data = np.prod(shape)
|
|
37
|
+
|
|
38
|
+
if return_integrals:
|
|
39
|
+
integrals.append(np.sum(np.abs(full_chgcar.data['total'])))
|
|
40
|
+
integrals[-1] /= n_data
|
|
41
|
+
if return_spin_integrals:
|
|
42
|
+
spin_integrals.append(np.sum(np.abs(full_chgcar.data['diff'])))
|
|
43
|
+
spin_integrals[-1] /= n_data
|
|
44
|
+
if verbose:
|
|
45
|
+
print("Shape of data: {}".format(shape))
|
|
46
|
+
print("Total number of datapoints: {}".format(n_data))
|
|
47
|
+
if return_integrals:
|
|
48
|
+
integral = integrals[-1]
|
|
49
|
+
else:
|
|
50
|
+
integral = np.sum(np.abs(full_chgcar.data['total']))
|
|
51
|
+
integral /= n_data
|
|
52
|
+
print("Integral of total data is {}".format(integral))
|
|
53
|
+
if spinpol:
|
|
54
|
+
if return_spin_integrals:
|
|
55
|
+
spin_integral = spin_integrals[-1]
|
|
56
|
+
else:
|
|
57
|
+
spin_integral = np.sum(np.abs(full_chgcar.data['diff']))
|
|
58
|
+
spin_integral /= n_data
|
|
59
|
+
print("Integral of diff data is {}".format(spin_integral))
|
|
60
|
+
|
|
61
|
+
origin = np.zeros(3)
|
|
62
|
+
atoms = AseAtomsAdaptor.get_atoms(full_chgcar.structure)
|
|
63
|
+
|
|
64
|
+
#Contrary to VASP Wiki, the CHGCAR is not rho*V, but rho*n_data.
|
|
65
|
+
#So in order to have the integral over space = nelectrons, we need to divide by n_data.
|
|
66
|
+
#Since this would result in super small numbers, we can transform to rho*V
|
|
67
|
+
factor = n_data
|
|
68
|
+
if mult_volume:
|
|
69
|
+
factor /= atoms.get_volume()
|
|
70
|
+
full_chgcar.data['total'] /= factor
|
|
71
|
+
if spinpol:
|
|
72
|
+
full_chgcar.data['diff'] /= factor
|
|
73
|
+
#write cube
|
|
74
|
+
filename = "{}.cube".format(outFiles[iFile])
|
|
75
|
+
if verbose:
|
|
76
|
+
print("Writing {}".format(filename))
|
|
77
|
+
with open(filename, 'w') as f:
|
|
78
|
+
write_cube(f, atoms, data=full_chgcar.data['total'], origin=origin)
|
|
79
|
+
if spinpol:
|
|
80
|
+
filename = "{}_mag.cube".format(outFiles[iFile])
|
|
81
|
+
if verbose:
|
|
82
|
+
print("Writing {}".format(filename))
|
|
83
|
+
with open(filename, 'w') as f:
|
|
84
|
+
write_cube(f, atoms, data=full_chgcar.data['diff'], origin=origin)
|
|
85
|
+
|
|
86
|
+
if return_integrals:
|
|
87
|
+
if len(integrals) == 1:
|
|
88
|
+
if return_spin_integrals:
|
|
89
|
+
return integrals[0], spin_integrals[0]
|
|
90
|
+
else:
|
|
91
|
+
return integrals[0]
|
|
92
|
+
else:
|
|
93
|
+
if return_spin_integrals:
|
|
94
|
+
return integrals, spin_integrals
|
|
95
|
+
else:
|
|
96
|
+
return integrals
|
|
97
|
+
else:
|
|
98
|
+
return
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
if __name__ == "__main__":
|
|
103
|
+
import argparse
|
|
104
|
+
parser = argparse.ArgumentParser(description='Convert one or many CHGCAR-like files to cube format.')
|
|
105
|
+
parser.add_argument('input', type=str, nargs='+', help='Input Files')
|
|
106
|
+
parser.add_argument('-output', type=str, nargs='+', help='Output File Names (no extension)')
|
|
107
|
+
parser.add_argument('-v', help='Verbose', action='store_true')
|
|
108
|
+
parser.add_argument('--integral', help='Print Integrals', action='store_true')
|
|
109
|
+
parser.add_argument('--volume', help='Multiply the Density with the Cell Volume', action='store_true')
|
|
110
|
+
args = parser.parse_args()
|
|
111
|
+
main(args.input, args.output, verbose=args.v, return_integrals=args.integral, mult_volume=args.volume)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
# Script to convert ELFCAR files to cube files
|
|
4
|
+
# by Patrick Melix
|
|
5
|
+
# 2022/04/04
|
|
6
|
+
#
|
|
7
|
+
# You can import the module and then call .main() or use it as a script
|
|
8
|
+
from pymatgen.io.vasp.outputs import Elfcar
|
|
9
|
+
from pymatgen.io.ase import AseAtomsAdaptor
|
|
10
|
+
from ase.io.cube import write_cube
|
|
11
|
+
import numpy as np
|
|
12
|
+
import os
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def main(inFiles, outFiles, verbose=True, return_integrals=False, return_spin_integrals=False):
|
|
16
|
+
assert len(inFiles) == len(outFiles), "Number of input and output files must be equal!"
|
|
17
|
+
integrals = []
|
|
18
|
+
spin_integrals = []
|
|
19
|
+
for iFile, inFile in enumerate(inFiles):
|
|
20
|
+
if not os.path.isfile(inFile):
|
|
21
|
+
raise ValueError('File {:} does not exist'.format(inFile))
|
|
22
|
+
|
|
23
|
+
# if output exists mv to .bak
|
|
24
|
+
if os.path.isfile(outFiles[iFile]):
|
|
25
|
+
if verbose:
|
|
26
|
+
print('ATTENTION: {:} exists, moving to *.bak'.format(outFiles[iFile]))
|
|
27
|
+
os.rename(outFiles[iFile], outFiles[iFile]+'.bak')
|
|
28
|
+
|
|
29
|
+
if verbose:
|
|
30
|
+
print("Reading {}".format(inFile))
|
|
31
|
+
full_elfcar = Elfcar.from_file(inFile)
|
|
32
|
+
spinpol = 'diff' in full_elfcar.data.keys()
|
|
33
|
+
#pymatgen: “total” key refers to Spin.up, and “diff” refers to Spin.down.
|
|
34
|
+
if return_spin_integrals and not spinpol:
|
|
35
|
+
raise ValueError("File {} is not spinpolarized!".format(inFile))
|
|
36
|
+
shape = full_elfcar.data['total'].shape
|
|
37
|
+
n_data = np.prod(shape)
|
|
38
|
+
|
|
39
|
+
if spinpol:
|
|
40
|
+
full_data = full_elfcar.data['total'] + full_elfcar.data['diff']
|
|
41
|
+
else:
|
|
42
|
+
full_data = full_elfcar.data['total']
|
|
43
|
+
|
|
44
|
+
if return_integrals:
|
|
45
|
+
integrals.append(np.sum(np.abs(full_data)))
|
|
46
|
+
if return_spin_integrals:
|
|
47
|
+
spin_integrals.append((np.sum(np.abs(full_elfcar.data['total'])), np.sum(np.abs(full_elfcar.data['diff']))))
|
|
48
|
+
if verbose:
|
|
49
|
+
print("Shape of data: {}".format(shape))
|
|
50
|
+
print("Total number of datapoints: {}".format(n_data))
|
|
51
|
+
if return_integrals:
|
|
52
|
+
integral = integrals[-1]
|
|
53
|
+
else:
|
|
54
|
+
integral = np.sum(np.abs(full_data))
|
|
55
|
+
print("Integral of total data is {}".format(integral))
|
|
56
|
+
if spinpol:
|
|
57
|
+
if return_spin_integrals:
|
|
58
|
+
spin_integral = spin_integrals[-1]
|
|
59
|
+
else:
|
|
60
|
+
spin_integral = (np.sum(np.abs(full_elfcar.data['total'])), np.sum(np.abs(full_elfcar.data['diff'])))
|
|
61
|
+
print("Integral of spin data is up: {}, down: {}".format(*spin_integral))
|
|
62
|
+
|
|
63
|
+
origin = np.zeros(3)
|
|
64
|
+
atoms = AseAtomsAdaptor.get_atoms(full_elfcar.structure)
|
|
65
|
+
|
|
66
|
+
# write cubes
|
|
67
|
+
if spinpol:
|
|
68
|
+
filename = "{}_up.cube".format(outFiles[iFile])
|
|
69
|
+
if verbose:
|
|
70
|
+
print("Writing {}".format(filename))
|
|
71
|
+
with open(filename, 'w') as f:
|
|
72
|
+
write_cube(f, atoms, data=full_elfcar.data['total'], origin=origin)
|
|
73
|
+
filename = "{}_down.cube".format(outFiles[iFile])
|
|
74
|
+
if verbose:
|
|
75
|
+
print("Writing {}".format(filename))
|
|
76
|
+
with open(filename, 'w') as f:
|
|
77
|
+
write_cube(f, atoms, data=full_elfcar.data['diff'], origin=origin)
|
|
78
|
+
filename = "{}_diff.cube".format(outFiles[iFile])
|
|
79
|
+
if verbose:
|
|
80
|
+
print("Writing {}".format(filename))
|
|
81
|
+
with open(filename, 'w') as f:
|
|
82
|
+
write_cube(f, atoms, data=full_elfcar.data['total']-full_elfcar.data['diff'], origin=origin)
|
|
83
|
+
else:
|
|
84
|
+
filename = "{}.cube".format(outFiles[iFile])
|
|
85
|
+
if verbose:
|
|
86
|
+
print("Writing {}".format(filename))
|
|
87
|
+
with open(filename, 'w') as f:
|
|
88
|
+
write_cube(f, atoms, data=full_data, origin=origin)
|
|
89
|
+
|
|
90
|
+
if return_integrals:
|
|
91
|
+
if len(integrals) == 1:
|
|
92
|
+
if return_spin_integrals:
|
|
93
|
+
return integrals[0], spin_integrals[0]
|
|
94
|
+
else:
|
|
95
|
+
return integrals[0]
|
|
96
|
+
else:
|
|
97
|
+
if return_spin_integrals:
|
|
98
|
+
return integrals, spin_integrals
|
|
99
|
+
else:
|
|
100
|
+
return integrals
|
|
101
|
+
else:
|
|
102
|
+
return
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
if __name__ == "__main__":
|
|
106
|
+
import argparse
|
|
107
|
+
parser = argparse.ArgumentParser(description='Convert one or many ELFCAR files to cube format.')
|
|
108
|
+
parser.add_argument('input', type=str, nargs='+', help='Input Files')
|
|
109
|
+
parser.add_argument('-output', type=str, nargs='+', help='Output File Names (no extension)')
|
|
110
|
+
parser.add_argument('-v', help='Verbose', action='store_true')
|
|
111
|
+
args = parser.parse_args()
|
|
112
|
+
main(args.input, args.output, verbose=args.v)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
from ase.calculators.vasp import Vasp
|
|
3
|
+
import os
|
|
4
|
+
os.environ['VASP_PP_PATH'] = "/home/patrickm/lib/vasp/ase"
|
|
5
|
+
|
|
6
|
+
calc = Vasp(restart=True, directory='./')
|
|
7
|
+
vibs = calc.get_vibrations()
|
|
8
|
+
vibs.write_jmol()
|
|
9
|
+
|
|
10
|
+
energies = vibs.get_energies()
|
|
11
|
+
nVibs = len(energies)
|
|
12
|
+
for i in range(nVibs):
|
|
13
|
+
with open("vib-{:03d}.xyz".format(i+1), 'w') as f:
|
|
14
|
+
for frame in vibs.iter_animated_mode(i):
|
|
15
|
+
frame.write(f, format='extxyz')
|
|
16
|
+
print("Frequency #{:03d}: {:10.6f} cm-1".format(i+1, energies[i]))
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
import argparse
|
|
3
|
+
import math
|
|
4
|
+
from ase.data import atomic_masses
|
|
5
|
+
import ase.io
|
|
6
|
+
from ase.units import _amu as amu, _me as me
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_atomic_mass(element_symbol):
|
|
10
|
+
mass_in_amu = atomic_masses[element_symbol]
|
|
11
|
+
# Convert mass to atomic units (1 amu = 1.66053904e-27 kg)
|
|
12
|
+
mass_in_au = mass_in_amu * amu / me
|
|
13
|
+
return mass_in_au
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def getAtomsFromOutcar(outcar_file):
|
|
17
|
+
atoms = ase.io.read(outcar_file)
|
|
18
|
+
return atoms
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def get_frequencies(outcar):
|
|
22
|
+
freqLines = []
|
|
23
|
+
for line in outcar:
|
|
24
|
+
if " f/i=" in line:
|
|
25
|
+
freqLines.append(line)
|
|
26
|
+
if "Eigenvectors after division by SQRT(mass)" in line:
|
|
27
|
+
break
|
|
28
|
+
return freqLines
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def generate_mw(frequency, atoms):
|
|
32
|
+
weights = atoms.get_masses()
|
|
33
|
+
freq_mw = []
|
|
34
|
+
for i in range(len(frequency)):
|
|
35
|
+
freq_line = frequency[i]
|
|
36
|
+
factor = math.sqrt(weights[i])
|
|
37
|
+
new_freq_line = []
|
|
38
|
+
for freq in freq_line:
|
|
39
|
+
if not freq == 0:
|
|
40
|
+
new_freq_line.append(freq / factor)
|
|
41
|
+
else:
|
|
42
|
+
new_freq_line.append(0.0)
|
|
43
|
+
freq_mw.append(new_freq_line)
|
|
44
|
+
return freq_mw
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def write_modecar(frequency, filename):
|
|
48
|
+
filestring = ""
|
|
49
|
+
for freq_line in frequency:
|
|
50
|
+
line = ""
|
|
51
|
+
for freq in freq_line:
|
|
52
|
+
if freq >= 0:
|
|
53
|
+
line += " "
|
|
54
|
+
else:
|
|
55
|
+
line += " "
|
|
56
|
+
line += "{:.10E}".format(freq)
|
|
57
|
+
filestring += line + "\n"
|
|
58
|
+
with open(filename, "w") as file:
|
|
59
|
+
file.write(filestring)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def read_frequency_from_outcar(outcar, freq_line, atoms):
|
|
63
|
+
current_frequency = []
|
|
64
|
+
start_index = outcar.index(freq_line) + 2
|
|
65
|
+
end_index = start_index + 0 + len(atoms)
|
|
66
|
+
for line in outcar[start_index:end_index]:
|
|
67
|
+
vals = line.split()
|
|
68
|
+
current_frequency.append([float(vals[3]), float(vals[4]), float(vals[5])])
|
|
69
|
+
return current_frequency
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
if __name__ == "__main__":
|
|
73
|
+
parser = argparse.ArgumentParser(
|
|
74
|
+
prog="freq2mode",
|
|
75
|
+
description="A VASP tool, which generates MODECAR and mass-weighted MODCAR files from frequency calculations",
|
|
76
|
+
epilog=""
|
|
77
|
+
)
|
|
78
|
+
parser.add_argument("-o", "--outcar", type=str, help="Optional: specify OUTCAR file", required=False, default="OUTCAR")
|
|
79
|
+
parser.add_argument("-i", "--index", type=int, help="Force non interactive mode by specifying the index of the imaginary frequency to use", required=False, default=-1)
|
|
80
|
+
args = parser.parse_args()
|
|
81
|
+
outcar_file = args.outcar
|
|
82
|
+
with open(outcar_file, "r") as f:
|
|
83
|
+
outcar = f.readlines()
|
|
84
|
+
atoms = getAtomsFromOutcar(outcar_file)
|
|
85
|
+
freqs = get_frequencies(outcar)
|
|
86
|
+
if len(freqs) == 0:
|
|
87
|
+
print("No imaginary frequencies found")
|
|
88
|
+
exit(0)
|
|
89
|
+
if len(freqs) < args.index + 1:
|
|
90
|
+
print("The specified mode was not found in the OUTCAR file")
|
|
91
|
+
exit(1)
|
|
92
|
+
if len(freqs) > 1:
|
|
93
|
+
print(f"Found {len(freqs)} imaginary frequencies. Select the frequency for MODECAR generation")
|
|
94
|
+
freq_index = 0
|
|
95
|
+
for freq in freqs:
|
|
96
|
+
print(f"{freq_index} {freq}")
|
|
97
|
+
freq_index += 1
|
|
98
|
+
if args.index == -1:
|
|
99
|
+
freq_index = int(input("Frequency for MODECAR generation:"))
|
|
100
|
+
else:
|
|
101
|
+
print(f"Using Frequency {args.index}")
|
|
102
|
+
freq_index = args.index
|
|
103
|
+
else:
|
|
104
|
+
print("Found one imaginary mode:")
|
|
105
|
+
print(freqs[0])
|
|
106
|
+
print("Using this mode for MODECAR generation")
|
|
107
|
+
freq_index = 0
|
|
108
|
+
frequency = read_frequency_from_outcar(outcar, freqs[freq_index], atoms)
|
|
109
|
+
print("Writing MODECAR file")
|
|
110
|
+
write_modecar(frequency, "MODECAR")
|
|
111
|
+
print("Writing mass-weighted MODECAR file")
|
|
112
|
+
frequency_mw = generate_mw(frequency, atoms)
|
|
113
|
+
write_modecar(frequency_mw, "MODECAR.MW")
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
# Script to get a KSPACING from a KPOINTS file and a POSCAR
|
|
4
|
+
# by Patrick Melix
|
|
5
|
+
# 2023/05/22
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_kspacing():
|
|
10
|
+
from ase import io
|
|
11
|
+
import numpy as np
|
|
12
|
+
mol = io.read('POSCAR')
|
|
13
|
+
cellparams = mol.cell.cellpar()
|
|
14
|
+
r_cell = mol.cell.reciprocal()
|
|
15
|
+
print("The cell parameters are |a|={} |b|={} |c|={} alpha={} beta={} gamma={}".format(*[ round(x,2) for x in cellparams]))
|
|
16
|
+
print("The reciprocal cell is: {}".format(r_cell))
|
|
17
|
+
with open('KPOINTS', 'r') as f:
|
|
18
|
+
kpoints = f.readlines()
|
|
19
|
+
if kpoints[1].strip() != "0":
|
|
20
|
+
raise ValueError("KPOINTS file does not use Automatic Scheme, but only this is supported!")
|
|
21
|
+
kgrid = [ int(k) for k in kpoints[3].split() ]
|
|
22
|
+
assert len(kgrid) == 3, "Expected to find 3 integers in line 4 of KPOINTS file!"
|
|
23
|
+
print("The KGRID from KPOINTS is: {} {} {}".format(*kgrid))
|
|
24
|
+
kspacing = [ np.linalg.norm(r_cell[i])*2*np.pi/kgrid[i] for i in range(3) ]
|
|
25
|
+
#kgrid = [ int(max(1, np.ceil(np.linalg.norm(r_cell[i])*2*np.pi/kspacing))) for i in range(3)]
|
|
26
|
+
print("The corresponding KSPACING for KGRID {} {} {} is {}Å^-1, {}Å^-1, {}Å^-1".format(*kgrid, *[ round(k, 3) for k in kspacing ]))
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
if __name__ == "__main__":
|
|
30
|
+
import argparse
|
|
31
|
+
parser = argparse.ArgumentParser(
|
|
32
|
+
description='Get a KSPACING from current POSCAR and KPOINTS')
|
|
33
|
+
args = parser.parse_args()
|
|
34
|
+
get_kspacing()
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
#
|
|
3
|
+
# Script to get a KGrid from a KSPACING value and a POSCAR
|
|
4
|
+
# by Patrick Melix
|
|
5
|
+
# 2023/05/22
|
|
6
|
+
#
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_kgrid(kspacing):
|
|
10
|
+
from ase import io
|
|
11
|
+
import numpy as np
|
|
12
|
+
mol = io.read('POSCAR')
|
|
13
|
+
cellparams = mol.cell.cellpar()
|
|
14
|
+
r_cell = mol.cell.reciprocal()
|
|
15
|
+
print("The cell parameters are |a|={} |b|={} |c|={} alpha={} beta={} gamma={}".format(*[ round(x,2) for x in cellparams]))
|
|
16
|
+
print("The reciprocal cell is: {}".format(r_cell))
|
|
17
|
+
kgrid = [ int(max(1, np.ceil(np.linalg.norm(r_cell[i])*2*np.pi/kspacing))) for i in range(3)]
|
|
18
|
+
print("The corresponding KGRID for KSPACING {}Å^-1 is: {} {} {}".format(kspacing, *kgrid))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
if __name__ == "__main__":
|
|
22
|
+
import argparse
|
|
23
|
+
parser = argparse.ArgumentParser(
|
|
24
|
+
description='Get a KGrid from current POSCAR and a KSPACING value')
|
|
25
|
+
parser.add_argument('kspacing', type=float, help='KSPACING value')
|
|
26
|
+
args = parser.parse_args()
|
|
27
|
+
get_kgrid(args.kspacing)
|