simpyson 0.0.1__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.
- simpyson-0.0.1/LICENSE.md +21 -0
- simpyson-0.0.1/MANIFEST.in +1 -0
- simpyson-0.0.1/PKG-INFO +70 -0
- simpyson-0.0.1/README.md +23 -0
- simpyson-0.0.1/pyproject.toml +147 -0
- simpyson-0.0.1/setup.cfg +4 -0
- simpyson-0.0.1/src/simpyson/__init__.py +8 -0
- simpyson-0.0.1/src/simpyson/cli.py +16 -0
- simpyson-0.0.1/src/simpyson/converter.py +188 -0
- simpyson-0.0.1/src/simpyson/gui.py +358 -0
- simpyson-0.0.1/src/simpyson/io.py +274 -0
- simpyson-0.0.1/src/simpyson/isotope_data.json +884 -0
- simpyson-0.0.1/src/simpyson/py.typed +0 -0
- simpyson-0.0.1/src/simpyson/templates.py +170 -0
- simpyson-0.0.1/src/simpyson.egg-info/PKG-INFO +70 -0
- simpyson-0.0.1/src/simpyson.egg-info/SOURCES.txt +18 -0
- simpyson-0.0.1/src/simpyson.egg-info/dependency_links.txt +1 -0
- simpyson-0.0.1/src/simpyson.egg-info/entry_points.txt +3 -0
- simpyson-0.0.1/src/simpyson.egg-info/requires.txt +21 -0
- simpyson-0.0.1/src/simpyson.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024
|
|
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 @@
|
|
|
1
|
+
graft src/simpyson
|
simpyson-0.0.1/PKG-INFO
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simpyson
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: A python interface to Simpson
|
|
5
|
+
Author-email: Carlos Bornes <carlos.bornes@natur.cuni.cz>
|
|
6
|
+
License: BSD-3
|
|
7
|
+
Project-URL: repository, https://github.com/carlosbornes/simpyson
|
|
8
|
+
Project-URL: documentation, https://carlosbornes.github.io/simpyson/
|
|
9
|
+
Project-URL: changelog, https://github.com/simpyson/simpyson/blob/main/CHANGELOG.md
|
|
10
|
+
Keywords: NMR,Simulation
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Science/Research
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Intended Audience :: Science/Research
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering
|
|
21
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
22
|
+
Classifier: Operating System :: Unix
|
|
23
|
+
Classifier: Operating System :: MacOS
|
|
24
|
+
Requires-Python: >=3.9
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
License-File: LICENSE.md
|
|
27
|
+
Requires-Dist: numpy
|
|
28
|
+
Requires-Dist: ase
|
|
29
|
+
Requires-Dist: pandas
|
|
30
|
+
Requires-Dist: soprano
|
|
31
|
+
Requires-Dist: plotly
|
|
32
|
+
Requires-Dist: PyQt5
|
|
33
|
+
Requires-Dist: PyQtWebEngine
|
|
34
|
+
Provides-Extra: dev
|
|
35
|
+
Requires-Dist: codecov-cli>=0.4.1; extra == "dev"
|
|
36
|
+
Requires-Dist: pytest>=7.4.0; extra == "dev"
|
|
37
|
+
Requires-Dist: pytest-cov>=3.0.0; extra == "dev"
|
|
38
|
+
Requires-Dist: ruff>=0.0.285; extra == "dev"
|
|
39
|
+
Provides-Extra: docs
|
|
40
|
+
Requires-Dist: mkdocs-material>=9.4.0; extra == "docs"
|
|
41
|
+
Requires-Dist: mkdocstrings[python]>=0.22.0; extra == "docs"
|
|
42
|
+
Requires-Dist: mkdocs-gen-files>=0.5.0; extra == "docs"
|
|
43
|
+
Requires-Dist: mkdocs-literate-nav>=0.6.0; extra == "docs"
|
|
44
|
+
Requires-Dist: pillow>=10.0.0; extra == "docs"
|
|
45
|
+
Requires-Dist: cairosvg>=2.7.1; extra == "docs"
|
|
46
|
+
Dynamic: license-file
|
|
47
|
+
|
|
48
|
+
# SimPYson: A Pythonic Interface for SIMPSON
|
|
49
|
+
|
|
50
|
+
[](https://doi.org/10.5281/zenodo.14041918)
|
|
51
|
+
|
|
52
|
+
SimPYson is a Python package designed to simplify the use of [SIMPSON](https://inano.au.dk/about/research-centers-and-projects/nmr/software/simpson), a powerful code to simulate solid-state NMR experiments. Born out of the need to streamline the process, SimPYson makes it easier to prepare input files from DFT calculations and analyze results from SIMPSON simulations all within a Python.
|
|
53
|
+
|
|
54
|
+
## Features 🤌
|
|
55
|
+
|
|
56
|
+
- **Convert DFT data to SIMPSON input files**: Prepare SIMPSON input files from DFT data (CASTEP, Quantum Espresso, VASP).
|
|
57
|
+
|
|
58
|
+
- **Read SIMPSON output files**: Load and manipulate NMR data from SIMPSON `.spe`, `.fid`, and `.xreim` files directly in Python for further analysis and visualization.
|
|
59
|
+
|
|
60
|
+
- **Templates for common experiments**: Use ready-made templates for typical Simpson NMR simulations, currently 90-degree pulse and no-pulse. More soon.
|
|
61
|
+
|
|
62
|
+
## Documentation 📖
|
|
63
|
+
|
|
64
|
+
To learn more about simpyson, including some tutorials check the [documentation](https://carlosbornes.github.io/simpyson/).
|
|
65
|
+
|
|
66
|
+
# Planned Features 🔜
|
|
67
|
+
|
|
68
|
+
- **Expand number of pulse sequences**: Additional templates for more complex NMR experiments.
|
|
69
|
+
|
|
70
|
+
- **Expand number of DFT codes**: Improve the support of other DFT codes, suggestions are welcomed.
|
simpyson-0.0.1/README.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# SimPYson: A Pythonic Interface for SIMPSON
|
|
2
|
+
|
|
3
|
+
[](https://doi.org/10.5281/zenodo.14041918)
|
|
4
|
+
|
|
5
|
+
SimPYson is a Python package designed to simplify the use of [SIMPSON](https://inano.au.dk/about/research-centers-and-projects/nmr/software/simpson), a powerful code to simulate solid-state NMR experiments. Born out of the need to streamline the process, SimPYson makes it easier to prepare input files from DFT calculations and analyze results from SIMPSON simulations all within a Python.
|
|
6
|
+
|
|
7
|
+
## Features 🤌
|
|
8
|
+
|
|
9
|
+
- **Convert DFT data to SIMPSON input files**: Prepare SIMPSON input files from DFT data (CASTEP, Quantum Espresso, VASP).
|
|
10
|
+
|
|
11
|
+
- **Read SIMPSON output files**: Load and manipulate NMR data from SIMPSON `.spe`, `.fid`, and `.xreim` files directly in Python for further analysis and visualization.
|
|
12
|
+
|
|
13
|
+
- **Templates for common experiments**: Use ready-made templates for typical Simpson NMR simulations, currently 90-degree pulse and no-pulse. More soon.
|
|
14
|
+
|
|
15
|
+
## Documentation 📖
|
|
16
|
+
|
|
17
|
+
To learn more about simpyson, including some tutorials check the [documentation](https://carlosbornes.github.io/simpyson/).
|
|
18
|
+
|
|
19
|
+
# Planned Features 🔜
|
|
20
|
+
|
|
21
|
+
- **Expand number of pulse sequences**: Additional templates for more complex NMR experiments.
|
|
22
|
+
|
|
23
|
+
- **Expand number of DFT codes**: Improve the support of other DFT codes, suggestions are welcomed.
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "simpyson"
|
|
7
|
+
description="A python interface to Simpson"
|
|
8
|
+
version = "0.0.1"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "BSD-3" }
|
|
11
|
+
authors = [{ name = "Carlos Bornes", email = "carlos.bornes@natur.cuni.cz" }]
|
|
12
|
+
keywords = ["NMR", "Simulation"]
|
|
13
|
+
classifiers = [
|
|
14
|
+
"Development Status :: 3 - Alpha",
|
|
15
|
+
"Intended Audience :: Science/Research",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.9",
|
|
18
|
+
"Programming Language :: Python :: 3.10",
|
|
19
|
+
"Programming Language :: Python :: 3.11",
|
|
20
|
+
"Programming Language :: Python :: 3.12",
|
|
21
|
+
"Programming Language :: Python :: 3.13",
|
|
22
|
+
"Intended Audience :: Science/Research",
|
|
23
|
+
"Topic :: Scientific/Engineering",
|
|
24
|
+
"Operating System :: Microsoft :: Windows",
|
|
25
|
+
"Operating System :: Unix",
|
|
26
|
+
"Operating System :: MacOS",
|
|
27
|
+
]
|
|
28
|
+
requires-python = ">=3.9"
|
|
29
|
+
dependencies = ["numpy", "ase", "pandas", "soprano", "plotly", "PyQt5", "PyQtWebEngine"]
|
|
30
|
+
|
|
31
|
+
[project.optional-dependencies]
|
|
32
|
+
dev = ["codecov-cli>=0.4.1", "pytest>=7.4.0", "pytest-cov>=3.0.0", "ruff>=0.0.285"]
|
|
33
|
+
docs = [
|
|
34
|
+
"mkdocs-material>=9.4.0",
|
|
35
|
+
"mkdocstrings[python]>=0.22.0",
|
|
36
|
+
"mkdocs-gen-files>=0.5.0",
|
|
37
|
+
"mkdocs-literate-nav>=0.6.0",
|
|
38
|
+
"pillow>=10.0.0",
|
|
39
|
+
"cairosvg>=2.7.1"
|
|
40
|
+
]
|
|
41
|
+
|
|
42
|
+
[project.urls]
|
|
43
|
+
repository = "https://github.com/carlosbornes/simpyson"
|
|
44
|
+
documentation = "https://carlosbornes.github.io/simpyson/"
|
|
45
|
+
changelog = "https://github.com/simpyson/simpyson/blob/main/CHANGELOG.md"
|
|
46
|
+
|
|
47
|
+
[project.scripts]
|
|
48
|
+
simpyson-gui = "simpyson.gui:main"
|
|
49
|
+
simpyson = "simpyson.cli:main"
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.package-data]
|
|
52
|
+
simpyson = ["py.typed", "isotope_data.json"]
|
|
53
|
+
|
|
54
|
+
[tool.pyright]
|
|
55
|
+
include = ["simpyson"]
|
|
56
|
+
exclude = ["**/__pycache__"]
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
minversion = "6.0"
|
|
60
|
+
addopts = ["-p no:warnings", "--import-mode=importlib"]
|
|
61
|
+
xfail_strict = true
|
|
62
|
+
log_cli_level = "warn"
|
|
63
|
+
pythonpath = "src"
|
|
64
|
+
testpaths = ["tests"]
|
|
65
|
+
|
|
66
|
+
[tool.black]
|
|
67
|
+
exclude = '''
|
|
68
|
+
/(
|
|
69
|
+
\.git
|
|
70
|
+
| \.tox
|
|
71
|
+
)/
|
|
72
|
+
'''
|
|
73
|
+
skip-magic-trailing-comma = true
|
|
74
|
+
|
|
75
|
+
[tool.isort]
|
|
76
|
+
profile = 'black'
|
|
77
|
+
skip_gitignore = true
|
|
78
|
+
|
|
79
|
+
[tool.coverage.run]
|
|
80
|
+
source = ["src"]
|
|
81
|
+
|
|
82
|
+
[tool.coverage.report]
|
|
83
|
+
exclude_also = [
|
|
84
|
+
"if TYPE_CHECKING:",
|
|
85
|
+
"if __name__ == .__main__.:",
|
|
86
|
+
"except ImportError",
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
[tool.ruff]
|
|
90
|
+
lint.select = [
|
|
91
|
+
"E", "F", "W", # flake8
|
|
92
|
+
"B", # flake8-bugbear
|
|
93
|
+
"I", # isort
|
|
94
|
+
"ARG", # flake8-unused-arguments
|
|
95
|
+
"C4", # flake8-comprehensions
|
|
96
|
+
"EM", # flake8-errmsg
|
|
97
|
+
"ICN", # flake8-import-conventions
|
|
98
|
+
"ISC", # flake8-implicit-str-concat
|
|
99
|
+
"G", # flake8-logging-format
|
|
100
|
+
"PGH", # pygrep-hooks
|
|
101
|
+
"PIE", # flake8-pie
|
|
102
|
+
"PL", # pylint
|
|
103
|
+
"PT", # flake8-pytest-style
|
|
104
|
+
"PTH", # flake8-use-pathlib
|
|
105
|
+
"RET", # flake8-return
|
|
106
|
+
"RUF", # Ruff-specific
|
|
107
|
+
"SIM", # flake8-simplify
|
|
108
|
+
"T20", # flake8-print
|
|
109
|
+
"UP", # pyupgrade
|
|
110
|
+
"YTT", # flake8-2020
|
|
111
|
+
"EXE", # flake8-executable
|
|
112
|
+
"NPY", # NumPy specific rules
|
|
113
|
+
"PD", # pandas-vet
|
|
114
|
+
]
|
|
115
|
+
lint.extend-ignore = [
|
|
116
|
+
"PLR", # Design related pylint codes
|
|
117
|
+
"E501", # Line too long
|
|
118
|
+
"B028", # No explicit stacklevel
|
|
119
|
+
"EM101", # Exception must not use a string literal
|
|
120
|
+
"EM102", # Exception must not use an f-string literal
|
|
121
|
+
"G004", # f-string in Logging statement
|
|
122
|
+
"RUF015", # Prefer next(iter())
|
|
123
|
+
"RET505", # Unnecessary `elif` after `return`
|
|
124
|
+
]
|
|
125
|
+
lint.typing-modules = ["mypackage._compat.typing"]
|
|
126
|
+
lint.unfixable = [
|
|
127
|
+
"T20", # Removes print statements
|
|
128
|
+
"F841", # Removes unused variables
|
|
129
|
+
]
|
|
130
|
+
lint.flake8-unused-arguments.ignore-variadic-names = true
|
|
131
|
+
lint.pydocstyle.convention = "numpy"
|
|
132
|
+
lint.isort.required-imports = ["from __future__ import annotations"]
|
|
133
|
+
lint.isort.known-first-party = ["simpyson"]
|
|
134
|
+
src = ["src"]
|
|
135
|
+
exclude = []
|
|
136
|
+
extend-exclude = ["tests"]
|
|
137
|
+
|
|
138
|
+
[tool.docformatter]
|
|
139
|
+
pre-summary-newline = true
|
|
140
|
+
black = true
|
|
141
|
+
|
|
142
|
+
[tool.mypy]
|
|
143
|
+
ignore_missing_imports = true
|
|
144
|
+
namespace_packages = true
|
|
145
|
+
explicit_package_bases = true
|
|
146
|
+
no_implicit_optional = false
|
|
147
|
+
disable_error_code = "annotation-unchecked"
|
simpyson-0.0.1/setup.cfg
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import argparse
|
|
2
|
+
from simpyson.gui import main as gui_main
|
|
3
|
+
|
|
4
|
+
def main():
|
|
5
|
+
parser = argparse.ArgumentParser(prog="simpyson")
|
|
6
|
+
subparsers = parser.add_subparsers(dest="command")
|
|
7
|
+
|
|
8
|
+
parser_gui = subparsers.add_parser("gui", help="Launch the GUI")
|
|
9
|
+
parser_gui.set_defaults(func=lambda args: gui_main())
|
|
10
|
+
|
|
11
|
+
args = parser.parse_args()
|
|
12
|
+
if hasattr(args, "func"):
|
|
13
|
+
args.func(args)
|
|
14
|
+
else:
|
|
15
|
+
parser.print_help()
|
|
16
|
+
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import ase.io
|
|
2
|
+
import numpy as np
|
|
3
|
+
import scipy.constants as const
|
|
4
|
+
import os
|
|
5
|
+
import json
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def read_vasp(file, format):
|
|
9
|
+
"""
|
|
10
|
+
This function reads NMR data from a VASP OUTCAR file.
|
|
11
|
+
|
|
12
|
+
Args:
|
|
13
|
+
file (str): The path to the VASP OUTCAR file.
|
|
14
|
+
format (str): The format of the VASP OUTCAR file.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
ase.Atoms: The Atoms object with the NMR data.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
reader = read_vasp('OUTCAR', 'vasp-out')
|
|
21
|
+
"""
|
|
22
|
+
filename = ase.io.read(file, format=format)
|
|
23
|
+
n_atoms = filename.get_global_number_of_atoms()
|
|
24
|
+
np.set_printoptions(suppress=True)
|
|
25
|
+
efg = []
|
|
26
|
+
sym_tensor = []
|
|
27
|
+
const_shield = []
|
|
28
|
+
core_shield_dict = []
|
|
29
|
+
ms = []
|
|
30
|
+
volume = None
|
|
31
|
+
with open(file, 'r') as outcar:
|
|
32
|
+
lines = outcar.readlines()
|
|
33
|
+
#Find lines with specific header
|
|
34
|
+
for line in lines:
|
|
35
|
+
if line.find("Electric field gradients (V/A^2)") != -1:
|
|
36
|
+
idx_header1 = lines.index(line) #efg
|
|
37
|
+
if line.find("SYMMETRIZED TENSORS") != -1:
|
|
38
|
+
idx_header2 = []
|
|
39
|
+
idx_header2.append(lines.index(line)) #sym tensor - need to take second one (unsym. tensors)
|
|
40
|
+
if line.find("G=0 CONTRIBUTION TO CHEMICAL SHIFT") != -1:
|
|
41
|
+
idx_header3 = lines.index(line) #constant shielding
|
|
42
|
+
if line.find('Core NMR properties') != -1:
|
|
43
|
+
idx_header4 = lines.index(line) #core NMR prop - depends on atom type
|
|
44
|
+
if line.find("Core contribution to magnetic susceptibility:") != -1:
|
|
45
|
+
val = line.split()[5]
|
|
46
|
+
exp = line.split()[6][-2:]
|
|
47
|
+
mag_sus = float(val)*10**int(exp)
|
|
48
|
+
if line.find("volume of cell") != -1 and volume is None:
|
|
49
|
+
volume = float(line.split()[4])
|
|
50
|
+
|
|
51
|
+
chi_fact = 3.0/8.0/np.pi*volume*6.022142e23/1e24 # Conversion factor for magnetic susceptibility
|
|
52
|
+
|
|
53
|
+
#Calculate tensors for every atoms
|
|
54
|
+
for i in range(n_atoms):
|
|
55
|
+
grad = (lines[idx_header1+4+i]).split()[1:] # V_xx, V_yy, V_zz, V_xy, V_xz, V_yz
|
|
56
|
+
matrix = np.array([[grad[0],grad[3],grad[4]], #xx xy xz
|
|
57
|
+
[grad[3],grad[1],grad[5]], #xy yy yz
|
|
58
|
+
[grad[4],grad[5],grad[2]]]) #xz yz zz
|
|
59
|
+
efg.append(matrix)
|
|
60
|
+
|
|
61
|
+
for i in range(n_atoms*4):
|
|
62
|
+
if i % 4 != 0:
|
|
63
|
+
sym=lines[idx_header2[-1] + i + 1].split()
|
|
64
|
+
sym_tensor.append(lines[idx_header2[-1] + i + 1].split())
|
|
65
|
+
|
|
66
|
+
# Newer version of VASP 6.4.1
|
|
67
|
+
if lines[idx_header3 + 1].strip() == "using pGv susceptibility, excluding core contribution":
|
|
68
|
+
start_idx = idx_header3 + 5
|
|
69
|
+
# Older version of VASP
|
|
70
|
+
else:
|
|
71
|
+
start_idx = idx_header3 + 4
|
|
72
|
+
|
|
73
|
+
for i in range(3):
|
|
74
|
+
const_shield.append((lines[start_idx + i]).split()[1:])
|
|
75
|
+
|
|
76
|
+
for i in range(len(np.unique(filename.get_chemical_symbols()))):
|
|
77
|
+
core_shield_dict.append((lines[idx_header4 + 4 + i]).split()[1:])
|
|
78
|
+
core_shield_dict = dict((k[0], float(k[1:][0])) for k in core_shield_dict)
|
|
79
|
+
core_shield = []
|
|
80
|
+
|
|
81
|
+
for i in filename.get_chemical_symbols():
|
|
82
|
+
core_shield.append(core_shield_dict[i])
|
|
83
|
+
|
|
84
|
+
#Process results
|
|
85
|
+
efg = np.array(efg,dtype=float) #resulting EFG matrix
|
|
86
|
+
efg = efg * 1e20 / const.physical_constants["atomic unit of electric field gradient"][0]
|
|
87
|
+
sym_tensor = np.split(np.array(sym_tensor,dtype=float), n_atoms) #symmetry tensors
|
|
88
|
+
const_shield = np.array(const_shield, dtype=float) #constant shielding of the lattice
|
|
89
|
+
core_shield = np.array(core_shield,dtype=float) #core shielding depending on atom type
|
|
90
|
+
|
|
91
|
+
for i in range(n_atoms):
|
|
92
|
+
core_diag = np.diag(core_shield[i] * np.ones(3))
|
|
93
|
+
ms_tensor = sym_tensor[i] + const_shield + core_diag + mag_sus/chi_fact*1e6*np.eye(3) #calculating MS tensor
|
|
94
|
+
ms.append(-ms_tensor) # calculating MS tensors
|
|
95
|
+
ms=np.array(np.array(ms).tolist(),dtype=float) #processing MS tensor to work with ase
|
|
96
|
+
|
|
97
|
+
filename.set_array('efg', efg)
|
|
98
|
+
filename.set_array('ms', ms)
|
|
99
|
+
|
|
100
|
+
return filename
|
|
101
|
+
|
|
102
|
+
def hz2ppm(hz, b0, nucleus, isotope_file=None):
|
|
103
|
+
"""
|
|
104
|
+
Convert Hz values to ppm values.
|
|
105
|
+
|
|
106
|
+
Args:
|
|
107
|
+
hz (numpy.ndarray): Frequency values in Hz
|
|
108
|
+
b0 (str): Magnetic field strength (e.g., '400MHz' or '9.4T')
|
|
109
|
+
nucleus (str): Nucleus type (e.g., '1H' or '13C')
|
|
110
|
+
isotope_file (str, optional): Path to isotope data file. If None, uses default.
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
numpy.ndarray: Chemical shift values in ppm
|
|
114
|
+
|
|
115
|
+
Raises:
|
|
116
|
+
ValueError: If B0 unit is invalid or nucleus not found
|
|
117
|
+
"""
|
|
118
|
+
|
|
119
|
+
if isotope_file is None:
|
|
120
|
+
dir = os.path.dirname(os.path.realpath(__file__))
|
|
121
|
+
isotope_file = os.path.join(dir, 'isotope_data.json')
|
|
122
|
+
|
|
123
|
+
isotope = int(''.join(filter(str.isdigit, nucleus)))
|
|
124
|
+
element = ''.join(filter(str.isalpha, nucleus)).upper()
|
|
125
|
+
b0_unit = ''.join(filter(str.isalpha, b0)).lower()
|
|
126
|
+
|
|
127
|
+
with open(isotope_file) as f:
|
|
128
|
+
data = json.load(f)
|
|
129
|
+
if element in data and str(isotope) in data[element]:
|
|
130
|
+
gamma = data[element][str(isotope)]['Gamma']
|
|
131
|
+
else:
|
|
132
|
+
raise ValueError(f'Nucleus {nucleus} not found in isotope data.')
|
|
133
|
+
|
|
134
|
+
if b0_unit == 't':
|
|
135
|
+
b0_value = float(''.join(filter(str.isdigit, b0)))
|
|
136
|
+
ppm = hz / (b0_value * gamma)
|
|
137
|
+
elif b0_unit == 'mhz':
|
|
138
|
+
b0_value = float(''.join(filter(str.isdigit, b0)))
|
|
139
|
+
gamma_h = data['H']['1']['Gamma']
|
|
140
|
+
ppm = hz / (b0_value/(gamma_h/gamma))
|
|
141
|
+
else:
|
|
142
|
+
raise ValueError('B0 unit must be T or MHz.')
|
|
143
|
+
|
|
144
|
+
return ppm
|
|
145
|
+
|
|
146
|
+
def ppm2hz(ppm, b0, nucleus, isotope_file=None):
|
|
147
|
+
"""
|
|
148
|
+
Convert ppm values to Hz values.
|
|
149
|
+
|
|
150
|
+
Args:
|
|
151
|
+
ppm (numpy.ndarray): Chemical shift values in ppm
|
|
152
|
+
b0 (str): Magnetic field strength (e.g., '400MHz' or '9.4T')
|
|
153
|
+
nucleus (str): Nucleus type (e.g., '1H' or '13C')
|
|
154
|
+
isotope_file (str, optional): Path to isotope data file. If None, uses default.
|
|
155
|
+
|
|
156
|
+
Returns:
|
|
157
|
+
numpy.ndarray: Frequency values in Hz
|
|
158
|
+
|
|
159
|
+
Raises:
|
|
160
|
+
ValueError: If B0 unit is invalid or nucleus not found
|
|
161
|
+
"""
|
|
162
|
+
|
|
163
|
+
if isotope_file is None:
|
|
164
|
+
dir = os.path.dirname(os.path.realpath(__file__))
|
|
165
|
+
isotope_file = os.path.join(dir, 'isotope_data.json')
|
|
166
|
+
|
|
167
|
+
isotope = int(''.join(filter(str.isdigit, nucleus)))
|
|
168
|
+
element = ''.join(filter(str.isalpha, nucleus)).upper()
|
|
169
|
+
b0_unit = ''.join(filter(str.isalpha, b0)).lower()
|
|
170
|
+
|
|
171
|
+
with open(isotope_file) as f:
|
|
172
|
+
data = json.load(f)
|
|
173
|
+
if element in data and str(isotope) in data[element]:
|
|
174
|
+
gamma = data[element][str(isotope)]['Gamma']
|
|
175
|
+
else:
|
|
176
|
+
raise ValueError(f'Nucleus {nucleus} not found in isotope data.')
|
|
177
|
+
|
|
178
|
+
if b0_unit == 't':
|
|
179
|
+
b0_value = float(''.join(filter(str.isdigit, b0)))
|
|
180
|
+
hz = ppm * (b0_value * gamma)
|
|
181
|
+
elif b0_unit == 'mhz':
|
|
182
|
+
b0_value = float(''.join(filter(str.isdigit, b0)))
|
|
183
|
+
gamma_h = data['H']['1']['Gamma']
|
|
184
|
+
hz = ppm * (b0_value/(gamma_h/gamma))
|
|
185
|
+
else:
|
|
186
|
+
raise ValueError('B0 unit must be T or MHz.')
|
|
187
|
+
|
|
188
|
+
return hz
|