atorvi 0.1.1__py3-none-any.whl
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.
- atorvi/__init__.py +36 -0
- atorvi/atomic_orbitals.py +624 -0
- atorvi/atorvi.py +392 -0
- atorvi-0.1.1.dist-info/LICENSE +21 -0
- atorvi-0.1.1.dist-info/METADATA +106 -0
- atorvi-0.1.1.dist-info/RECORD +9 -0
- atorvi-0.1.1.dist-info/WHEEL +5 -0
- atorvi-0.1.1.dist-info/entry_points.txt +2 -0
- atorvi-0.1.1.dist-info/top_level.txt +1 -0
atorvi/__init__.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"""
|
|
2
|
+
atorvi - ATomic ORbitals VIsualization
|
|
3
|
+
a library for visualizing individual atomic orbitals and their various linear combinations.
|
|
4
|
+
The result is a file in .xsf format, which can be opened and visualized using software like XCrysDen or VESTA.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
__author__ = "Dmitry Korotin"
|
|
8
|
+
__author_email__ = "dmitry@korotin.name"
|
|
9
|
+
__version__ = "0.1.1"
|
|
10
|
+
__license__ = "MIT"
|
|
11
|
+
|
|
12
|
+
from .atomic_orbitals import (
|
|
13
|
+
radial_part,
|
|
14
|
+
get_orbital,
|
|
15
|
+
supported_orbitals,
|
|
16
|
+
p_orbitals,
|
|
17
|
+
d_orbitals,
|
|
18
|
+
f_orbitals,
|
|
19
|
+
get_atomic_number
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
from .atorvi import (
|
|
23
|
+
OrbitalFile,
|
|
24
|
+
main
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
'OrbitalFile',
|
|
29
|
+
'radial_part',
|
|
30
|
+
'get_orbital',
|
|
31
|
+
'supported_orbitals',
|
|
32
|
+
'p_orbitals',
|
|
33
|
+
'd_orbitals',
|
|
34
|
+
'f_orbitals',
|
|
35
|
+
'get_atomic_number'
|
|
36
|
+
]
|
|
@@ -0,0 +1,624 @@
|
|
|
1
|
+
__author__ = "Dmitry Korotin"
|
|
2
|
+
__author_email__ = "dmitry@korotin.name"
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from scipy.special import sph_harm, genlaguerre, factorial
|
|
6
|
+
|
|
7
|
+
p_orbitals = ["p_z", "p_x", "p_y"]
|
|
8
|
+
d_orbitals = ["d_{3z^2-r^2}", "d_{xz}", "d_{yz}", "d_{xy}", "d_{x^2-y^2}"]
|
|
9
|
+
f_orbitals = [
|
|
10
|
+
"f_{z^3}",
|
|
11
|
+
"f_{xz^2}",
|
|
12
|
+
"f_{yz^2}",
|
|
13
|
+
"f_{xyz}",
|
|
14
|
+
"f_{z(x^2-y^2)}",
|
|
15
|
+
"f_{x(x^2-3y^2)}",
|
|
16
|
+
"f_{y(3x^2-y^2)}"
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
supported_orbitals = ["s"] + p_orbitals + d_orbitals + f_orbitals
|
|
20
|
+
|
|
21
|
+
def get_atomic_number(element_name):
|
|
22
|
+
"""
|
|
23
|
+
Returns the atomic number of the given element.
|
|
24
|
+
|
|
25
|
+
This function takes the symbol of a chemical element and returns its
|
|
26
|
+
corresponding atomic number from the periodic table. If the element is
|
|
27
|
+
not found, the function returns None.
|
|
28
|
+
|
|
29
|
+
Parameters:
|
|
30
|
+
----------
|
|
31
|
+
element_name : str
|
|
32
|
+
The symbol of the chemical element (e.g., 'H' for hydrogen, 'O' for oxygen).
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
-------
|
|
36
|
+
int or None
|
|
37
|
+
The atomic number of the element if it is found, otherwise None.
|
|
38
|
+
"""
|
|
39
|
+
# fmt: off
|
|
40
|
+
periodic_table = {
|
|
41
|
+
'H': 1, 'He': 2, 'Li': 3, 'Be': 4, 'B': 5, 'C': 6, 'N': 7, 'O': 8, 'F': 9, 'Ne': 10,
|
|
42
|
+
'Na': 11, 'Mg': 12, 'Al': 13, 'Si': 14, 'P': 15, 'S': 16, 'Cl': 17, 'Ar': 18,
|
|
43
|
+
'K': 19, 'Ca': 20, 'Sc': 21, 'Ti': 22, 'V': 23, 'Cr': 24, 'Mn': 25, 'Fe': 26,
|
|
44
|
+
'Co': 27, 'Ni': 28, 'Cu': 29, 'Zn': 30, 'Ga': 31, 'Ge': 32, 'As': 33, 'Se': 34,
|
|
45
|
+
'Br': 35, 'Kr': 36, 'Rb': 37, 'Sr': 38, 'Y': 39, 'Zr': 40, 'Nb': 41, 'Mo': 42,
|
|
46
|
+
'Tc': 43, 'Ru': 44, 'Rh': 45, 'Pd': 46, 'Ag': 47, 'Cd': 48, 'In': 49, 'Sn': 50,
|
|
47
|
+
'Sb': 51, 'Te': 52, 'I': 53, 'Xe': 54, 'Cs': 55, 'Ba': 56, 'La': 57, 'Ce': 58,
|
|
48
|
+
'Pr': 59, 'Nd': 60, 'Pm': 61, 'Sm': 62, 'Eu': 63, 'Gd': 64, 'Tb': 65, 'Dy': 66,
|
|
49
|
+
'Ho': 67, 'Er': 68, 'Tm': 69, 'Yb': 70, 'Lu': 71, 'Hf': 72, 'Ta': 73, 'W': 74,
|
|
50
|
+
'Re': 75, 'Os': 76, 'Ir': 77, 'Pt': 78, 'Au': 79, 'Hg': 80, 'Tl': 81, 'Pb': 82,
|
|
51
|
+
'Bi': 83, 'Th': 90, 'Pa': 91, 'U': 92, 'Np': 93, 'Pu': 94, 'Am': 95, 'Cm': 96,
|
|
52
|
+
'Bk': 97, 'Cf': 98, 'Es': 99, 'Fm': 100, 'Md': 101, 'No': 102, 'Lr': 103,
|
|
53
|
+
'Rf': 104, 'Db': 105, 'Sg': 106, 'Bh': 107, 'Hs': 108, 'Mt': 109, 'Ds': 110,
|
|
54
|
+
'Rg': 111, 'Cn': 112, 'Nh': 113, 'Fl': 114, 'Mc': 115, 'Lv': 116, 'Ts': 117,
|
|
55
|
+
'Og': 118
|
|
56
|
+
}
|
|
57
|
+
# fmt: on
|
|
58
|
+
return periodic_table.get(element_name)
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def cart2sph(x, y, z):
|
|
62
|
+
"""
|
|
63
|
+
Convert Cartesian coordinates to spherical coordinates.
|
|
64
|
+
|
|
65
|
+
This function converts Cartesian coordinates (x, y, z) into spherical
|
|
66
|
+
coordinates (r, theta, phi). The spherical coordinates are defined as follows:
|
|
67
|
+
- r: the radial distance from the origin,
|
|
68
|
+
- theta: the polar angle (angle from the z-axis),
|
|
69
|
+
- phi: the azimuthal angle (angle from the x-axis in the xy-plane).
|
|
70
|
+
|
|
71
|
+
Parameters:
|
|
72
|
+
----------
|
|
73
|
+
x : float
|
|
74
|
+
The x-coordinate in Cartesian coordinates.
|
|
75
|
+
y : float
|
|
76
|
+
The y-coordinate in Cartesian coordinates.
|
|
77
|
+
z : float
|
|
78
|
+
The z-coordinate in Cartesian coordinates.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
-------
|
|
82
|
+
np.ndarray
|
|
83
|
+
A numpy array containing the spherical coordinates [r, theta, phi].
|
|
84
|
+
"""
|
|
85
|
+
xy_sq = x**2 + y**2
|
|
86
|
+
r = np.sqrt(xy_sq + z**2)
|
|
87
|
+
theta = np.arctan2(np.sqrt(xy_sq), z)
|
|
88
|
+
phi = np.arctan2(y, x)
|
|
89
|
+
|
|
90
|
+
return np.array([r, theta, phi])
|
|
91
|
+
|
|
92
|
+
def radial_part(r, l, z):
|
|
93
|
+
"""
|
|
94
|
+
Compute the radial part of the hydrogen-like atomic wavefunction.
|
|
95
|
+
|
|
96
|
+
Parameters:
|
|
97
|
+
r (float or ndarray): Radial distance from the nucleus in Bohr radii
|
|
98
|
+
l (int): Orbital angular momentum quantum number (0 <= l < n)
|
|
99
|
+
z (int): Atomic number (for hydrogen, Z=1)
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
R_nl (float or ndarray): Radial wavefunction value(s) at r
|
|
103
|
+
"""
|
|
104
|
+
# Bohr radius
|
|
105
|
+
a_0 = 0.52917720859
|
|
106
|
+
|
|
107
|
+
# define principal quantum number from z
|
|
108
|
+
if z < 3:
|
|
109
|
+
n = 1
|
|
110
|
+
elif z < 11:
|
|
111
|
+
n = 2
|
|
112
|
+
elif z < 19 or z in range(21, 31):
|
|
113
|
+
n = 3
|
|
114
|
+
elif z < 37 or z in range(39, 49) or z in range(57, 72):
|
|
115
|
+
n = 4
|
|
116
|
+
elif z < 55 or z in range(72, 81) or z in range(89, 104):
|
|
117
|
+
n = 5
|
|
118
|
+
|
|
119
|
+
# Use tabulated screened nuclear charge (Clementi's by default and Slater's if not available)
|
|
120
|
+
zeff = Z_EFF[z][l]
|
|
121
|
+
|
|
122
|
+
# Prefactor
|
|
123
|
+
rho = 2 * zeff * r / (n * a_0)
|
|
124
|
+
norm_factor = np.sqrt((2 * zeff / (n * a_0))**3 * factorial(n - l - 1) / (2 * n * factorial(n + l)))
|
|
125
|
+
|
|
126
|
+
# Laguerre polynomial
|
|
127
|
+
L = genlaguerre(n - l - 1, 2 * l + 1)
|
|
128
|
+
|
|
129
|
+
# Radial wavefunction
|
|
130
|
+
R_nl = norm_factor * np.exp(-rho/2.0) * rho**l * L(rho)
|
|
131
|
+
|
|
132
|
+
return R_nl
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def get_orbital(orb, sph_coords, z):
|
|
136
|
+
"""
|
|
137
|
+
Calculate the value of a specific atomic orbital at given spherical coordinates.
|
|
138
|
+
|
|
139
|
+
This function computes the value of a specified atomic orbital at given
|
|
140
|
+
spherical coordinates for an atom with the given atomic number.
|
|
141
|
+
|
|
142
|
+
Parameters:
|
|
143
|
+
----------
|
|
144
|
+
orb : str
|
|
145
|
+
The type of orbital (e.g., "s", "p_x", "d_{xy}", etc.).
|
|
146
|
+
sph_coords : numpy.ndarray
|
|
147
|
+
An array of spherical coordinates [r, theta, phi].
|
|
148
|
+
z : int
|
|
149
|
+
The atomic number of the element.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
-------
|
|
153
|
+
float
|
|
154
|
+
The value of the atomic orbital at the given coordinates.
|
|
155
|
+
"""
|
|
156
|
+
|
|
157
|
+
r = sph_coords[0]
|
|
158
|
+
theta = sph_coords[1]
|
|
159
|
+
phi = sph_coords[2]
|
|
160
|
+
# fmt: off
|
|
161
|
+
if orb == "s":
|
|
162
|
+
orbital = np.real( radial_part(r,0,z)*sph_harm(0, 0, phi,theta) )
|
|
163
|
+
elif orb == "p_z":
|
|
164
|
+
orbital = np.real( radial_part(r,1,z)*(sph_harm(0, 1, phi,theta)) )
|
|
165
|
+
elif orb == "p_x":
|
|
166
|
+
orbital = np.real( radial_part(r,1,z)*(1/np.sqrt(2.0))*(sph_harm(-1, 1, phi,theta)-sph_harm(1, 1, phi,theta)) )
|
|
167
|
+
elif orb == "p_y":
|
|
168
|
+
orbital = np.real( radial_part(r,1,z)*(1j/np.sqrt(2.0))*(sph_harm(-1, 1, phi,theta)+sph_harm(1, 1, phi,theta)) )
|
|
169
|
+
elif orb == "d_{3z^2-r^2}":
|
|
170
|
+
orbital = np.real( radial_part(r,2,z)*sph_harm(0, 2, phi,theta) )
|
|
171
|
+
elif orb == "d_{xz}":
|
|
172
|
+
orbital = np.real( radial_part(r,2,z)*(1/np.sqrt(2.0))*(sph_harm(-1, 2, phi,theta) - sph_harm(1, 2, phi,theta)) )
|
|
173
|
+
elif orb == "d_{yz}":
|
|
174
|
+
orbital = np.real( radial_part(r,2,z)*(1j/np.sqrt(2.0))*(sph_harm(-1, 2, phi,theta) + sph_harm(1, 2, phi,theta)) )
|
|
175
|
+
elif orb == "d_{xy}":
|
|
176
|
+
orbital = np.real( radial_part(r,2,z)*(1j/np.sqrt(2.0))*(sph_harm(-2, 2, phi,theta) - sph_harm(2, 2, phi,theta)) )
|
|
177
|
+
elif orb == "d_{x^2-y^2}":
|
|
178
|
+
orbital = np.real( radial_part(r,2,z)*(1/np.sqrt(2.0))*(sph_harm(-2, 2, phi,theta) + sph_harm(2, 2, phi,theta)))
|
|
179
|
+
elif orb == "f_{z^3}":
|
|
180
|
+
orbital = np.real( radial_part(r,3,z)*sph_harm(0, 3, phi,theta) )
|
|
181
|
+
elif orb == "f_{xz^2}":
|
|
182
|
+
orbital = np.real( radial_part(r,3,z)*(1/np.sqrt(2.0))*(sph_harm(-1, 3, phi,theta) - sph_harm(1, 3, phi,theta)) )
|
|
183
|
+
elif orb == "f_{yz^2}":
|
|
184
|
+
orbital = np.real( radial_part(r,3,z)*(1j/np.sqrt(2.0))*(sph_harm(-1, 3, phi,theta) + sph_harm(1, 3, phi,theta)) )
|
|
185
|
+
elif orb == "f_{xyz}":
|
|
186
|
+
orbital = np.real( radial_part(r,3,z)*(1j/np.sqrt(2.0))*(sph_harm(-2, 3, phi,theta) - sph_harm(2, 3, phi,theta)) )
|
|
187
|
+
elif orb == "f_{z(x^2-y^2)}":
|
|
188
|
+
orbital = np.real( radial_part(r,3,z)*(1/np.sqrt(2.0))*(sph_harm(-2, 3, phi,theta) + sph_harm(2, 3, phi,theta)) )
|
|
189
|
+
elif orb == "f_{x(x^2-3y^2)}":
|
|
190
|
+
orbital = np.real( radial_part(r,3,z)*(1/np.sqrt(2.0))*(sph_harm(-3, 3, phi,theta) - sph_harm(3, 3, phi,theta)) )
|
|
191
|
+
elif orb == "f_{y(3x^2-y^2)}":
|
|
192
|
+
orbital = np.real( radial_part(r,3,z)*(1j/np.sqrt(2.0))*(sph_harm(-3, 3, phi,theta) + sph_harm(3, 3, phi,theta)) )
|
|
193
|
+
else:
|
|
194
|
+
raise ValueError(f"Unknown orbital: {orb}")
|
|
195
|
+
# fmt: on
|
|
196
|
+
|
|
197
|
+
return orbital
|
|
198
|
+
|
|
199
|
+
# Effective nuclear charge using Clementi or Slater method (when Clementi is not available).
|
|
200
|
+
Z_EFF = {
|
|
201
|
+
1: {0: 1.0, 1: 1.0, 2: 0.30000000000000004, 3: 0.30000000000000004},
|
|
202
|
+
2: {0: 1.6875, 1: 1.7, 2: 0.30000000000000004, 3: 0.30000000000000004},
|
|
203
|
+
3: {0: 1.2792, 1: 1.3, 2: 0.3500000000000001, 3: 0.3500000000000001},
|
|
204
|
+
4: {
|
|
205
|
+
0: 1.912,
|
|
206
|
+
1: 1.9500000000000002,
|
|
207
|
+
2: 0.3500000000000001,
|
|
208
|
+
3: 0.3500000000000001,
|
|
209
|
+
},
|
|
210
|
+
5: {0: 2.5762, 1: 2.4214, 2: 0.34999999999999964, 3: 0.34999999999999964},
|
|
211
|
+
6: {0: 3.2166, 1: 3.1358, 2: 0.34999999999999964, 3: 0.34999999999999964},
|
|
212
|
+
7: {0: 3.8474, 1: 3.834, 2: 0.34999999999999964, 3: 0.34999999999999964},
|
|
213
|
+
8: {0: 4.4916, 1: 4.4532, 2: 0.34999999999999964, 3: 0.34999999999999964},
|
|
214
|
+
9: {0: 5.1276, 1: 5.1, 2: 0.34999999999999964, 3: 0.34999999999999964},
|
|
215
|
+
10: {0: 5.7584, 1: 5.7584, 2: 0.34999999999999964, 3: 0.34999999999999964},
|
|
216
|
+
11: {
|
|
217
|
+
0: 2.5074000000000005,
|
|
218
|
+
1: 2.1999999999999993,
|
|
219
|
+
2: 0.34999999999999964,
|
|
220
|
+
3: 0.34999999999999964,
|
|
221
|
+
},
|
|
222
|
+
12: {
|
|
223
|
+
0: 3.307500000000001,
|
|
224
|
+
1: 2.8499999999999996,
|
|
225
|
+
2: 0.34999999999999964,
|
|
226
|
+
3: 0.34999999999999964,
|
|
227
|
+
},
|
|
228
|
+
13: {0: 4.1172, 1: 4.0656, 2: 0.34999999999999964, 3: 0.34999999999999964},
|
|
229
|
+
14: {0: 4.9032, 1: 4.2852, 2: 0.34999999999999964, 3: 0.34999999999999964},
|
|
230
|
+
15: {0: 5.6418, 1: 4.8864, 2: 0.34999999999999964, 3: 0.34999999999999964},
|
|
231
|
+
16: {
|
|
232
|
+
0: 6.366900000000001,
|
|
233
|
+
1: 5.4818999999999996,
|
|
234
|
+
2: 0.34999999999999964,
|
|
235
|
+
3: 0.34999999999999964,
|
|
236
|
+
},
|
|
237
|
+
17: {
|
|
238
|
+
0: 7.068300000000001,
|
|
239
|
+
1: 6.116099999999999,
|
|
240
|
+
2: 0.3500000000000014,
|
|
241
|
+
3: 0.3500000000000014,
|
|
242
|
+
},
|
|
243
|
+
18: {
|
|
244
|
+
0: 7.7568,
|
|
245
|
+
1: 6.764100000000001,
|
|
246
|
+
2: 0.3500000000000014,
|
|
247
|
+
3: 0.3500000000000014,
|
|
248
|
+
},
|
|
249
|
+
19: {
|
|
250
|
+
0: 3.4952000000000005,
|
|
251
|
+
1: 2.1999999999999993,
|
|
252
|
+
2: 0.3500000000000014,
|
|
253
|
+
3: 0.3500000000000014,
|
|
254
|
+
},
|
|
255
|
+
20: {
|
|
256
|
+
0: 4.398,
|
|
257
|
+
1: 2.849999999999998,
|
|
258
|
+
2: 0.3500000000000014,
|
|
259
|
+
3: 0.3500000000000014,
|
|
260
|
+
},
|
|
261
|
+
21: {0: 10.3398, 1: 9.4062, 2: 7.1198999999999995, 3: 2.3500000000000014},
|
|
262
|
+
22: {0: 11.033100000000001, 1: 10.1037, 2: 8.1414, 3: 2.3500000000000014},
|
|
263
|
+
23: {0: 11.709299999999999, 1: 10.785, 2: 8.9829, 3: 2.3500000000000014},
|
|
264
|
+
24: {0: 12.3678, 1: 11.466000000000001, 2: 9.7566, 3: 1.3500000000000014},
|
|
265
|
+
25: {0: 13.0179, 1: 12.109200000000001, 2: 10.5282, 3: 2.3500000000000014},
|
|
266
|
+
26: {0: 13.6761, 1: 12.777899999999999, 2: 11.1798, 3: 2.3500000000000014},
|
|
267
|
+
27: {0: 14.322299999999998, 1: 13.4346, 2: 11.8554, 3: 2.3500000000000014},
|
|
268
|
+
28: {0: 14.961, 1: 14.085, 2: 12.529499999999999, 3: 2.3500000000000014},
|
|
269
|
+
29: {0: 15.5943, 1: 14.730599999999999, 2: 13.2006, 3: 1.3500000000000014},
|
|
270
|
+
30: {0: 16.2192, 1: 15.369299999999999, 2: 13.8783, 3: 2.3500000000000014},
|
|
271
|
+
31: {
|
|
272
|
+
0: 7.066800000000001,
|
|
273
|
+
1: 6.221599999999999,
|
|
274
|
+
2: 0.3500000000000014,
|
|
275
|
+
3: 0.3500000000000014,
|
|
276
|
+
},
|
|
277
|
+
32: {
|
|
278
|
+
0: 8.043599999999998,
|
|
279
|
+
1: 6.7804,
|
|
280
|
+
2: 0.3500000000000014,
|
|
281
|
+
3: 0.3500000000000014,
|
|
282
|
+
},
|
|
283
|
+
33: {
|
|
284
|
+
0: 8.944000000000003,
|
|
285
|
+
1: 7.449200000000001,
|
|
286
|
+
2: 0.3500000000000014,
|
|
287
|
+
3: 0.3500000000000014,
|
|
288
|
+
},
|
|
289
|
+
34: {
|
|
290
|
+
0: 9.7576,
|
|
291
|
+
1: 8.287199999999999,
|
|
292
|
+
2: 0.3500000000000014,
|
|
293
|
+
3: 0.3500000000000014,
|
|
294
|
+
},
|
|
295
|
+
35: {
|
|
296
|
+
0: 10.552799999999998,
|
|
297
|
+
1: 9.027999999999999,
|
|
298
|
+
2: 0.3500000000000014,
|
|
299
|
+
3: 0.3500000000000014,
|
|
300
|
+
},
|
|
301
|
+
36: {
|
|
302
|
+
0: 11.3156,
|
|
303
|
+
1: 9.769199999999998,
|
|
304
|
+
2: 0.3500000000000014,
|
|
305
|
+
3: 0.3500000000000014,
|
|
306
|
+
},
|
|
307
|
+
37: {
|
|
308
|
+
0: 4.984499999999997,
|
|
309
|
+
1: 2.200000000000003,
|
|
310
|
+
2: 0.3500000000000014,
|
|
311
|
+
3: 0.3500000000000014,
|
|
312
|
+
},
|
|
313
|
+
38: {
|
|
314
|
+
0: 6.070499999999999,
|
|
315
|
+
1: 2.8500000000000014,
|
|
316
|
+
2: 0.3500000000000014,
|
|
317
|
+
3: 0.3500000000000014,
|
|
318
|
+
},
|
|
319
|
+
39: {0: 14.2636, 1: 12.7456, 2: 15.958399999999997, 3: 2.3500000000000014},
|
|
320
|
+
40: {0: 14.901600000000002, 1: 13.46, 2: 13.0716, 3: 2.3500000000000014},
|
|
321
|
+
41: {
|
|
322
|
+
0: 15.282800000000002,
|
|
323
|
+
1: 14.084400000000002,
|
|
324
|
+
2: 11.2376,
|
|
325
|
+
3: 1.3500000000000014,
|
|
326
|
+
},
|
|
327
|
+
42: {0: 16.0964, 1: 14.9768, 2: 11.392400000000002, 3: 1.3500000000000014},
|
|
328
|
+
43: {0: 17.1984, 1: 15.8112, 2: 12.881999999999998, 3: 2.3500000000000014},
|
|
329
|
+
44: {0: 17.656, 1: 16.4348, 2: 12.8128, 3: 1.3500000000000014},
|
|
330
|
+
45: {0: 18.5816, 1: 17.1396, 2: 13.4424, 3: 1.3500000000000014},
|
|
331
|
+
46: {0: 18.986, 1: 17.7232, 2: 13.617599999999996, 3: 0.3500000000000014},
|
|
332
|
+
47: {0: 19.8648, 1: 18.5624, 2: 14.762799999999999, 3: 1.3500000000000014},
|
|
333
|
+
48: {0: 20.8692, 1: 19.4112, 2: 15.876800000000003, 3: 2.3500000000000014},
|
|
334
|
+
49: {
|
|
335
|
+
0: 9.511499999999998,
|
|
336
|
+
1: 8.469999999999999,
|
|
337
|
+
2: 0.3500000000000014,
|
|
338
|
+
3: 0.3500000000000014,
|
|
339
|
+
},
|
|
340
|
+
50: {
|
|
341
|
+
0: 10.628500000000003,
|
|
342
|
+
1: 9.102000000000004,
|
|
343
|
+
2: 0.3500000000000014,
|
|
344
|
+
3: 0.3500000000000014,
|
|
345
|
+
},
|
|
346
|
+
51: {
|
|
347
|
+
0: 11.611000000000004,
|
|
348
|
+
1: 9.994500000000002,
|
|
349
|
+
2: 0.3500000000000014,
|
|
350
|
+
3: 0.3500000000000014,
|
|
351
|
+
},
|
|
352
|
+
52: {
|
|
353
|
+
0: 12.537999999999997,
|
|
354
|
+
1: 10.808500000000002,
|
|
355
|
+
2: 0.3500000000000014,
|
|
356
|
+
3: 0.3500000000000014,
|
|
357
|
+
},
|
|
358
|
+
53: {
|
|
359
|
+
0: 13.403500000000001,
|
|
360
|
+
1: 11.6115,
|
|
361
|
+
2: 0.3500000000000014,
|
|
362
|
+
3: 0.3500000000000014,
|
|
363
|
+
},
|
|
364
|
+
54: {
|
|
365
|
+
0: 14.218000000000004,
|
|
366
|
+
1: 12.424500000000002,
|
|
367
|
+
2: 0.3500000000000014,
|
|
368
|
+
3: 0.3500000000000014,
|
|
369
|
+
},
|
|
370
|
+
55: {
|
|
371
|
+
0: 15.444500000000005,
|
|
372
|
+
1: 13.650999999999996,
|
|
373
|
+
2: 1.3500000000000014,
|
|
374
|
+
3: 1.3500000000000014,
|
|
375
|
+
},
|
|
376
|
+
56: {
|
|
377
|
+
0: 16.619500000000002,
|
|
378
|
+
1: 14.8005,
|
|
379
|
+
2: 2.3500000000000014,
|
|
380
|
+
3: 2.3500000000000014,
|
|
381
|
+
},
|
|
382
|
+
57: {0: 28.7964, 1: 27.7064, 2: 24.7252, 3: 1.3599999999999994},
|
|
383
|
+
58: {0: 29.68, 1: 28.6064, 2: 25.660799999999995, 3: 1.676000000000002},
|
|
384
|
+
59: {0: 30.3332, 1: 29.0568, 2: 26.297200000000004, 3: 21.1008},
|
|
385
|
+
60: {0: 30.9864, 1: 30.014, 2: 26.809200000000004, 3: 22.266},
|
|
386
|
+
61: {0: 31.6396, 1: 30.6232, 2: 27.739999999999995, 3: 23.134},
|
|
387
|
+
62: {0: 32.2924, 1: 31.088, 2: 28.239599999999996, 3: 23.531599999999997},
|
|
388
|
+
63: {0: 32.868, 1: 31.8748, 2: 28.940799999999996, 3: 24.32},
|
|
389
|
+
64: {0: 33.444, 1: 32.6468, 2: 29.6336, 3: 25.013599999999997},
|
|
390
|
+
65: {0: 34.02, 1: 33.3988, 2: 30.310000000000002, 3: 25.864800000000002},
|
|
391
|
+
66: {0: 34.592, 1: 33.826, 2: 31.018, 3: 26.536},
|
|
392
|
+
67: {0: 35.312, 1: 34.5628, 2: 31.671599999999998, 3: 27.4696},
|
|
393
|
+
68: {0: 36.232, 1: 35.1092, 2: 32.2712, 3: 27.9784},
|
|
394
|
+
69: {0: 37.1376, 1: 35.988, 2: 32.944, 3: 28.634},
|
|
395
|
+
70: {0: 37.5176, 1: 36.402, 2: 33.5896, 3: 29.432000000000002},
|
|
396
|
+
71: {0: 38.2692, 1: 37.1904, 2: 35.2892, 3: 30.931200000000004},
|
|
397
|
+
72: {0: 21.833, 1: 19.585, 2: 16.619500000000002, 3: 2.3499999999999943},
|
|
398
|
+
73: {0: 22.6935, 1: 20.4735, 2: 16.368000000000002, 3: 2.3499999999999943},
|
|
399
|
+
74: {
|
|
400
|
+
0: 23.5415,
|
|
401
|
+
1: 21.325500000000005,
|
|
402
|
+
2: 16.741999999999997,
|
|
403
|
+
3: 2.3499999999999943,
|
|
404
|
+
},
|
|
405
|
+
75: {0: 24.357, 1: 22.144, 2: 17.382999999999996, 3: 2.3499999999999943},
|
|
406
|
+
76: {0: 25.095, 1: 22.909999999999997, 2: 17.997, 3: 2.3499999999999943},
|
|
407
|
+
77: {0: 25.8455, 1: 23.661, 2: 18.695999999999998, 3: 2.3499999999999943},
|
|
408
|
+
78: {0: 26.587999999999994, 1: 24.4195, 2: 19.4075, 3: 1.3499999999999943},
|
|
409
|
+
79: {0: 27.3275, 1: 25.17, 2: 20.1265, 3: 1.3499999999999943},
|
|
410
|
+
80: {
|
|
411
|
+
0: 28.111000000000004,
|
|
412
|
+
1: 25.967,
|
|
413
|
+
2: 20.855999999999995,
|
|
414
|
+
3: 2.3499999999999943,
|
|
415
|
+
},
|
|
416
|
+
81: {
|
|
417
|
+
0: 29.122,
|
|
418
|
+
1: 27.088499999999996,
|
|
419
|
+
2: 22.025000000000006,
|
|
420
|
+
3: 3.3499999999999943,
|
|
421
|
+
},
|
|
422
|
+
82: {0: 30.131500000000003, 1: 28.03, 2: 23.152, 3: 4.349999999999994},
|
|
423
|
+
83: {0: 31.028999999999996, 1: 29.021, 2: 24.244, 3: 5.349999999999994},
|
|
424
|
+
84: {
|
|
425
|
+
0: 32.023,
|
|
426
|
+
1: 30.024500000000003,
|
|
427
|
+
2: 25.304000000000002,
|
|
428
|
+
3: 6.349999999999994,
|
|
429
|
+
},
|
|
430
|
+
85: {0: 32.9335, 1: 31.04, 2: 26.339, 3: 7.349999999999994},
|
|
431
|
+
86: {0: 33.893, 1: 31.970999999999997, 2: 27.353, 3: 8.349999999999994},
|
|
432
|
+
87: {
|
|
433
|
+
0: 29.349999999999994,
|
|
434
|
+
1: 29.349999999999994,
|
|
435
|
+
2: 15.849999999999994,
|
|
436
|
+
3: 9.349999999999994,
|
|
437
|
+
},
|
|
438
|
+
88: {
|
|
439
|
+
0: 30.349999999999994,
|
|
440
|
+
1: 30.349999999999994,
|
|
441
|
+
2: 16.849999999999994,
|
|
442
|
+
3: 10.349999999999994,
|
|
443
|
+
},
|
|
444
|
+
89: {
|
|
445
|
+
0: 31.349999999999994,
|
|
446
|
+
1: 31.349999999999994,
|
|
447
|
+
2: 17.849999999999994,
|
|
448
|
+
3: 11.349999999999994,
|
|
449
|
+
},
|
|
450
|
+
90: {
|
|
451
|
+
0: 32.349999999999994,
|
|
452
|
+
1: 32.349999999999994,
|
|
453
|
+
2: 18.849999999999994,
|
|
454
|
+
3: 12.349999999999994,
|
|
455
|
+
},
|
|
456
|
+
91: {
|
|
457
|
+
0: 33.349999999999994,
|
|
458
|
+
1: 33.349999999999994,
|
|
459
|
+
2: 17.849999999999994,
|
|
460
|
+
3: 12.650000000000006,
|
|
461
|
+
},
|
|
462
|
+
92: {
|
|
463
|
+
0: 34.349999999999994,
|
|
464
|
+
1: 34.349999999999994,
|
|
465
|
+
2: 17.849999999999994,
|
|
466
|
+
3: 13.299999999999997,
|
|
467
|
+
},
|
|
468
|
+
93: {
|
|
469
|
+
0: 35.349999999999994,
|
|
470
|
+
1: 35.349999999999994,
|
|
471
|
+
2: 17.849999999999994,
|
|
472
|
+
3: 13.950000000000003,
|
|
473
|
+
},
|
|
474
|
+
94: {
|
|
475
|
+
0: 36.349999999999994,
|
|
476
|
+
1: 36.349999999999994,
|
|
477
|
+
2: 16.849999999999994,
|
|
478
|
+
3: 14.25,
|
|
479
|
+
},
|
|
480
|
+
95: {
|
|
481
|
+
0: 37.349999999999994,
|
|
482
|
+
1: 37.349999999999994,
|
|
483
|
+
2: 16.849999999999994,
|
|
484
|
+
3: 14.900000000000006,
|
|
485
|
+
},
|
|
486
|
+
96: {
|
|
487
|
+
0: 38.349999999999994,
|
|
488
|
+
1: 38.349999999999994,
|
|
489
|
+
2: 17.849999999999994,
|
|
490
|
+
3: 15.900000000000006,
|
|
491
|
+
},
|
|
492
|
+
97: {
|
|
493
|
+
0: 39.349999999999994,
|
|
494
|
+
1: 39.349999999999994,
|
|
495
|
+
2: 16.849999999999994,
|
|
496
|
+
3: 16.200000000000003,
|
|
497
|
+
},
|
|
498
|
+
98: {
|
|
499
|
+
0: 40.349999999999994,
|
|
500
|
+
1: 40.349999999999994,
|
|
501
|
+
2: 16.849999999999994,
|
|
502
|
+
3: 16.849999999999994,
|
|
503
|
+
},
|
|
504
|
+
99: {
|
|
505
|
+
0: 41.349999999999994,
|
|
506
|
+
1: 41.349999999999994,
|
|
507
|
+
2: 16.849999999999994,
|
|
508
|
+
3: 17.5,
|
|
509
|
+
},
|
|
510
|
+
100: {
|
|
511
|
+
0: 42.349999999999994,
|
|
512
|
+
1: 42.349999999999994,
|
|
513
|
+
2: 16.849999999999994,
|
|
514
|
+
3: 18.150000000000006,
|
|
515
|
+
},
|
|
516
|
+
101: {
|
|
517
|
+
0: 43.349999999999994,
|
|
518
|
+
1: 43.349999999999994,
|
|
519
|
+
2: 16.849999999999994,
|
|
520
|
+
3: 18.799999999999997,
|
|
521
|
+
},
|
|
522
|
+
102: {
|
|
523
|
+
0: 44.349999999999994,
|
|
524
|
+
1: 44.349999999999994,
|
|
525
|
+
2: 16.849999999999994,
|
|
526
|
+
3: 19.450000000000003,
|
|
527
|
+
},
|
|
528
|
+
103: {
|
|
529
|
+
0: 45.349999999999994,
|
|
530
|
+
1: 45.349999999999994,
|
|
531
|
+
2: 17.849999999999994,
|
|
532
|
+
3: 20.450000000000003,
|
|
533
|
+
},
|
|
534
|
+
104: {
|
|
535
|
+
0: 46.349999999999994,
|
|
536
|
+
1: 46.349999999999994,
|
|
537
|
+
2: 18.849999999999994,
|
|
538
|
+
3: 21.450000000000003,
|
|
539
|
+
},
|
|
540
|
+
105: {
|
|
541
|
+
0: 47.349999999999994,
|
|
542
|
+
1: 47.349999999999994,
|
|
543
|
+
2: 19.849999999999994,
|
|
544
|
+
3: 22.450000000000003,
|
|
545
|
+
},
|
|
546
|
+
106: {
|
|
547
|
+
0: 48.349999999999994,
|
|
548
|
+
1: 48.349999999999994,
|
|
549
|
+
2: 20.849999999999994,
|
|
550
|
+
3: 23.450000000000003,
|
|
551
|
+
},
|
|
552
|
+
107: {
|
|
553
|
+
0: 49.349999999999994,
|
|
554
|
+
1: 49.349999999999994,
|
|
555
|
+
2: 21.849999999999994,
|
|
556
|
+
3: 24.450000000000003,
|
|
557
|
+
},
|
|
558
|
+
108: {
|
|
559
|
+
0: 50.349999999999994,
|
|
560
|
+
1: 50.349999999999994,
|
|
561
|
+
2: 22.849999999999994,
|
|
562
|
+
3: 25.450000000000003,
|
|
563
|
+
},
|
|
564
|
+
109: {
|
|
565
|
+
0: 51.349999999999994,
|
|
566
|
+
1: 51.349999999999994,
|
|
567
|
+
2: 23.849999999999994,
|
|
568
|
+
3: 26.450000000000003,
|
|
569
|
+
},
|
|
570
|
+
110: {
|
|
571
|
+
0: 52.349999999999994,
|
|
572
|
+
1: 52.349999999999994,
|
|
573
|
+
2: 24.849999999999994,
|
|
574
|
+
3: 27.450000000000003,
|
|
575
|
+
},
|
|
576
|
+
111: {
|
|
577
|
+
0: 53.349999999999994,
|
|
578
|
+
1: 53.349999999999994,
|
|
579
|
+
2: 25.849999999999994,
|
|
580
|
+
3: 28.450000000000003,
|
|
581
|
+
},
|
|
582
|
+
112: {
|
|
583
|
+
0: 54.349999999999994,
|
|
584
|
+
1: 54.349999999999994,
|
|
585
|
+
2: 26.849999999999994,
|
|
586
|
+
3: 29.450000000000003,
|
|
587
|
+
},
|
|
588
|
+
113: {
|
|
589
|
+
0: 55.349999999999994,
|
|
590
|
+
1: 55.349999999999994,
|
|
591
|
+
2: 27.849999999999994,
|
|
592
|
+
3: 30.450000000000003,
|
|
593
|
+
},
|
|
594
|
+
114: {
|
|
595
|
+
0: 56.349999999999994,
|
|
596
|
+
1: 56.349999999999994,
|
|
597
|
+
2: 28.849999999999994,
|
|
598
|
+
3: 31.450000000000003,
|
|
599
|
+
},
|
|
600
|
+
115: {
|
|
601
|
+
0: 57.349999999999994,
|
|
602
|
+
1: 57.349999999999994,
|
|
603
|
+
2: 29.849999999999994,
|
|
604
|
+
3: 32.45,
|
|
605
|
+
},
|
|
606
|
+
116: {
|
|
607
|
+
0: 58.349999999999994,
|
|
608
|
+
1: 58.349999999999994,
|
|
609
|
+
2: 30.849999999999994,
|
|
610
|
+
3: 33.45,
|
|
611
|
+
},
|
|
612
|
+
117: {
|
|
613
|
+
0: 59.349999999999994,
|
|
614
|
+
1: 59.349999999999994,
|
|
615
|
+
2: 31.849999999999994,
|
|
616
|
+
3: 34.45,
|
|
617
|
+
},
|
|
618
|
+
118: {
|
|
619
|
+
0: 60.349999999999994,
|
|
620
|
+
1: 60.349999999999994,
|
|
621
|
+
2: 32.849999999999994,
|
|
622
|
+
3: 35.45,
|
|
623
|
+
},
|
|
624
|
+
}
|
atorvi/atorvi.py
ADDED
|
@@ -0,0 +1,392 @@
|
|
|
1
|
+
__author__ = "Dmitry Korotin"
|
|
2
|
+
__author_email__ = "dmitry@korotin.name"
|
|
3
|
+
|
|
4
|
+
import numpy as np
|
|
5
|
+
from .atomic_orbitals import *
|
|
6
|
+
|
|
7
|
+
class OrbitalFile:
|
|
8
|
+
"""
|
|
9
|
+
A class for creating and managing files containing atomic orbital data.
|
|
10
|
+
|
|
11
|
+
This class provides methods for adding atoms and orbitals, setting up the
|
|
12
|
+
computational box, and writing the orbital data to a file.
|
|
13
|
+
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, filename, grid_step=0.05) -> None:
|
|
17
|
+
self.file = open(filename, "w")
|
|
18
|
+
self.box_origin = [-2, -2, -2]
|
|
19
|
+
self.box_size = [4, 4, 4]
|
|
20
|
+
self.orbitals = []
|
|
21
|
+
self.grid_step = grid_step
|
|
22
|
+
self.atoms = []
|
|
23
|
+
self.is_crystal = False
|
|
24
|
+
|
|
25
|
+
def __del__(self):
|
|
26
|
+
if not self.file.closed:
|
|
27
|
+
self.file.close()
|
|
28
|
+
|
|
29
|
+
def _calculate_orbital_grid(self, orbital, position=[0.0, 0.0, 0.0], znumber=8):
|
|
30
|
+
|
|
31
|
+
origin = self.box_origin - position
|
|
32
|
+
x = np.linspace(origin[0], origin[0] + self.box_size[0], self.grid[0])
|
|
33
|
+
y = np.linspace(origin[1], origin[1] + self.box_size[1], self.grid[1])
|
|
34
|
+
z = np.linspace(origin[2], origin[2] + self.box_size[2], self.grid[2])
|
|
35
|
+
|
|
36
|
+
xx, yy, zz = np.meshgrid(x, y, z, indexing="ij")
|
|
37
|
+
|
|
38
|
+
sph_coords = cart2sph(xx, yy, zz)
|
|
39
|
+
|
|
40
|
+
orbital_grid = get_orbital(orbital, sph_coords, znumber)
|
|
41
|
+
|
|
42
|
+
return orbital_grid
|
|
43
|
+
|
|
44
|
+
def _write_orbitals(self, squared):
|
|
45
|
+
|
|
46
|
+
self._generate_box()
|
|
47
|
+
|
|
48
|
+
for orb in self.orbitals:
|
|
49
|
+
self.datagrid += orb[3] * self._calculate_orbital_grid(
|
|
50
|
+
orb[0], orb[1], orb[2]
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
if squared:
|
|
54
|
+
self.datagrid = self.datagrid**2
|
|
55
|
+
|
|
56
|
+
self.file.write("\nBEGIN_BLOCK_DATAGRID_3D\nmy_datagrid\n")
|
|
57
|
+
self.file.write("BEGIN_DATAGRID_3D\n")
|
|
58
|
+
self.file.write(f"{self.grid[0]} {self.grid[1]} {self.grid[2]}\n")
|
|
59
|
+
self.file.write(
|
|
60
|
+
f"{self.box_origin[0]} {self.box_origin[1]} {self.box_origin[2]}\n"
|
|
61
|
+
)
|
|
62
|
+
self.file.write(f"{self.box_size[0]} 0 0\n")
|
|
63
|
+
self.file.write(f"0 {self.box_size[1]} 0\n")
|
|
64
|
+
self.file.write(f"0 0 {self.box_size[2]}\n")
|
|
65
|
+
|
|
66
|
+
outdata = self.datagrid.T
|
|
67
|
+
for vec in outdata:
|
|
68
|
+
np.savetxt(self.file, vec, fmt="%12.9f", footer=" ", comments="")
|
|
69
|
+
|
|
70
|
+
self.file.write("END_DATAGRID_3D\n")
|
|
71
|
+
self.file.write("END_BLOCK_DATAGRID_3D\n")
|
|
72
|
+
|
|
73
|
+
def _write_atoms(self):
|
|
74
|
+
|
|
75
|
+
if self.is_crystal:
|
|
76
|
+
self.file.write("CRYSTAL\nPRIMVEC\n")
|
|
77
|
+
self.file.writelines(
|
|
78
|
+
f"{row[0]:9.6f} {row[1]:9.6f} {row[2]:9.6f}\n"
|
|
79
|
+
for row in self.lattice.matrix
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
self.file.write("CONVVEC\n")
|
|
83
|
+
self.file.writelines(
|
|
84
|
+
f"{row[0]:9.6f} {row[1]:9.6f} {row[2]:9.6f}\n"
|
|
85
|
+
for row in self.lattice.matrix
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
self.file.write("PRIMCOORD\n")
|
|
89
|
+
self.file.write(f"{len(self.atoms)} 1\n")
|
|
90
|
+
else:
|
|
91
|
+
|
|
92
|
+
self.file.write("ATOMS\n")
|
|
93
|
+
|
|
94
|
+
for at in self.atoms:
|
|
95
|
+
atomic_number = get_atomic_number(at[0])
|
|
96
|
+
x, y, z = at[1]
|
|
97
|
+
self.file.write(f"{atomic_number:3n} {x:9.6f} {y:9.6f} {z:9.6f}\n")
|
|
98
|
+
|
|
99
|
+
def add_atoms(self, atoms):
|
|
100
|
+
"""
|
|
101
|
+
Add atoms to the system.
|
|
102
|
+
|
|
103
|
+
This method adds atoms to the system if it's not a periodic system.
|
|
104
|
+
|
|
105
|
+
Parameters:
|
|
106
|
+
----------
|
|
107
|
+
atoms : list
|
|
108
|
+
A list of atoms to add, where each atom is represented by a tuple
|
|
109
|
+
containing the element symbol and its coordinates.
|
|
110
|
+
|
|
111
|
+
Raises:
|
|
112
|
+
------
|
|
113
|
+
ValueError
|
|
114
|
+
If the system is periodic (crystal structure).
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
if not self.is_crystal:
|
|
118
|
+
for a in atoms:
|
|
119
|
+
self.atoms.append(a)
|
|
120
|
+
else:
|
|
121
|
+
raise ValueError("It is a periodic system. Do not add atoms manually")
|
|
122
|
+
|
|
123
|
+
def write_data(self, squared=False):
|
|
124
|
+
"""
|
|
125
|
+
Write the orbital and atom data to the file.
|
|
126
|
+
|
|
127
|
+
This method writes the atom positions and orbital data to the file
|
|
128
|
+
and closes it.
|
|
129
|
+
"""
|
|
130
|
+
|
|
131
|
+
if len(self.atoms) > 0:
|
|
132
|
+
self._write_atoms()
|
|
133
|
+
|
|
134
|
+
if len(self.orbitals) > 0:
|
|
135
|
+
self._write_orbitals( squared )
|
|
136
|
+
|
|
137
|
+
print(f"\nFile {self.file.name} successfully written")
|
|
138
|
+
|
|
139
|
+
self.file.close()
|
|
140
|
+
|
|
141
|
+
def _generate_box(self):
|
|
142
|
+
min_orbital_size = 5.0
|
|
143
|
+
|
|
144
|
+
orbitals_positions = [orb[1] for orb in self.orbitals]
|
|
145
|
+
|
|
146
|
+
box_center, box_size = get_bbox_center_and_size(orbitals_positions)
|
|
147
|
+
|
|
148
|
+
box_size += [min_orbital_size, min_orbital_size, min_orbital_size]
|
|
149
|
+
self.box_size = np.array(box_size)
|
|
150
|
+
|
|
151
|
+
self.box_origin = box_center - self.box_size / 2.0
|
|
152
|
+
|
|
153
|
+
self.grid = np.array(self.box_size // self.grid_step, dtype=int)
|
|
154
|
+
self.datagrid = np.zeros(self.grid)
|
|
155
|
+
|
|
156
|
+
def add_orbital(self, orbital, position=[0.0, 0.0, 0.0], znumber=8, coeff=1.0):
|
|
157
|
+
"""
|
|
158
|
+
Add an orbital to the system.
|
|
159
|
+
|
|
160
|
+
This method adds an orbital with specified parameters to the system.
|
|
161
|
+
|
|
162
|
+
Parameters:
|
|
163
|
+
----------
|
|
164
|
+
orbital : str
|
|
165
|
+
The type of orbital (e.g., "s", "p_x", "d_{xy}", etc.).
|
|
166
|
+
position : list, optional
|
|
167
|
+
The position of the orbital (default is [0.0, 0.0, 0]).
|
|
168
|
+
znumber : int, optional
|
|
169
|
+
The atomic number of the element (default is 8).
|
|
170
|
+
coeff : float, optional
|
|
171
|
+
The coefficient of the orbital (default is 1.0).
|
|
172
|
+
"""
|
|
173
|
+
self.orbitals.append([orbital, position, znumber, coeff])
|
|
174
|
+
|
|
175
|
+
def add_orbital_at_atom(self, orbital, atom_index, coeff=1.0):
|
|
176
|
+
"""
|
|
177
|
+
Add an orbital at a specific atom's position.
|
|
178
|
+
|
|
179
|
+
This method adds an orbital at the position of a specified atom.
|
|
180
|
+
|
|
181
|
+
Parameters:
|
|
182
|
+
----------
|
|
183
|
+
orbital : str
|
|
184
|
+
The type of orbital (e.g., "s", "p_x", "d_{xy}", etc.).
|
|
185
|
+
atom_index : int
|
|
186
|
+
The index of the atom in the system.
|
|
187
|
+
coeff : float, optional
|
|
188
|
+
The coefficient of the orbital (default is 1.0).
|
|
189
|
+
|
|
190
|
+
Raises:
|
|
191
|
+
------
|
|
192
|
+
KeyError
|
|
193
|
+
If the atom_index is out of range.
|
|
194
|
+
"""
|
|
195
|
+
if atom_index in range(0, len(self.atoms)):
|
|
196
|
+
position = self.atoms[atom_index][1]
|
|
197
|
+
znumber = get_atomic_number(self.atoms[atom_index][0])
|
|
198
|
+
self.orbitals.append([orbital, position, znumber, coeff])
|
|
199
|
+
else:
|
|
200
|
+
raise KeyError("Wrong atom_index")
|
|
201
|
+
|
|
202
|
+
def crystal_from_file(self, filename):
|
|
203
|
+
"""
|
|
204
|
+
Create a crystal structure from a file.
|
|
205
|
+
|
|
206
|
+
This method reads a crystal structure from a file and sets up the system.
|
|
207
|
+
|
|
208
|
+
Parameters:
|
|
209
|
+
----------
|
|
210
|
+
filename : str
|
|
211
|
+
The path to the file containing the crystal structure.
|
|
212
|
+
|
|
213
|
+
Returns:
|
|
214
|
+
-------
|
|
215
|
+
pymatgen.core.structure.IStructure
|
|
216
|
+
The created crystal structure.
|
|
217
|
+
"""
|
|
218
|
+
try:
|
|
219
|
+
from pymatgen.core.structure import IStructure
|
|
220
|
+
except ImportError:
|
|
221
|
+
raise ImportError(
|
|
222
|
+
"\nOptional dependency 'pymatgen' required for crystal_from_file is not installed. \n\
|
|
223
|
+
You can install it by running: pip install pymatgen"
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
structure = IStructure.from_file(filename)
|
|
227
|
+
self.crystal_from_pymatgen(structure)
|
|
228
|
+
|
|
229
|
+
return structure
|
|
230
|
+
|
|
231
|
+
def crystal_from_pymatgen(self, structure):
|
|
232
|
+
"""
|
|
233
|
+
Set up the crystal structure from a pymatgen Structure object.
|
|
234
|
+
|
|
235
|
+
This method sets up the crystal structure using a pymatgen Structure object.
|
|
236
|
+
|
|
237
|
+
Parameters:
|
|
238
|
+
----------
|
|
239
|
+
structure : pymatgen.core.structure.IStructure
|
|
240
|
+
The pymatgen Structure object representing the crystal.
|
|
241
|
+
"""
|
|
242
|
+
|
|
243
|
+
crystal = structure
|
|
244
|
+
self.is_crystal = True
|
|
245
|
+
|
|
246
|
+
self.lattice = crystal.lattice
|
|
247
|
+
|
|
248
|
+
for atom in crystal.sites:
|
|
249
|
+
self.atoms.append((atom.specie.symbol, atom.coords))
|
|
250
|
+
|
|
251
|
+
def add_orbital_at_element(self, orbital, element, coeff=1.0):
|
|
252
|
+
"""
|
|
253
|
+
Add an orbital to all atoms of a specific element.
|
|
254
|
+
|
|
255
|
+
This method adds the specified orbital to all atoms of the given element.
|
|
256
|
+
|
|
257
|
+
Parameters:
|
|
258
|
+
----------
|
|
259
|
+
orbital : str
|
|
260
|
+
The type of orbital (e.g., "s", "p_x", "d_{xy}", etc.).
|
|
261
|
+
element : str
|
|
262
|
+
The symbol of the element.
|
|
263
|
+
coeff : float, optional
|
|
264
|
+
The coefficient of the orbital (default is 1.0).
|
|
265
|
+
"""
|
|
266
|
+
for iatom, atom in enumerate(self.atoms):
|
|
267
|
+
if element == atom[0]:
|
|
268
|
+
self.add_orbital_at_atom(orbital, iatom, coeff)
|
|
269
|
+
|
|
270
|
+
def get_bbox_center_and_size(points):
|
|
271
|
+
"""
|
|
272
|
+
Calculate the center and size of a bounding box for a set of points.
|
|
273
|
+
|
|
274
|
+
This function takes a list of points and calculates the center and size of
|
|
275
|
+
the smallest bounding box that contains all the points.
|
|
276
|
+
|
|
277
|
+
Parameters:
|
|
278
|
+
----------
|
|
279
|
+
points : list of tuples or numpy.ndarray
|
|
280
|
+
A list of points, where each point is represented by a tuple or array
|
|
281
|
+
of coordinates.
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
-------
|
|
285
|
+
tuple
|
|
286
|
+
A tuple containing two numpy arrays:
|
|
287
|
+
- center: The coordinates of the center of the bounding box.
|
|
288
|
+
- bounding_box_size: The size of the bounding box in each dimension.
|
|
289
|
+
"""
|
|
290
|
+
points_array = np.array(points)
|
|
291
|
+
|
|
292
|
+
center = np.mean(points_array, axis=0)
|
|
293
|
+
distances = points_array - center
|
|
294
|
+
max_distances = np.max(np.abs(distances), axis=0)
|
|
295
|
+
bounding_box_size = 2 * max_distances
|
|
296
|
+
|
|
297
|
+
return center, bounding_box_size
|
|
298
|
+
|
|
299
|
+
def main():
|
|
300
|
+
"""
|
|
301
|
+
Interactive mode for atorvi orbital visualization.
|
|
302
|
+
Allows users to specify orbitals and their positions interactively.
|
|
303
|
+
"""
|
|
304
|
+
from importlib.metadata import version
|
|
305
|
+
|
|
306
|
+
print("\nATORVI - ATomic ORbital VIsualization")
|
|
307
|
+
print(f"Version: {version('atorvi')}")
|
|
308
|
+
print(f"Author: {__author__}")
|
|
309
|
+
print(f"Contact: {__author_email__}\n")
|
|
310
|
+
|
|
311
|
+
# Get output filename
|
|
312
|
+
filename = input("Enter output filename (e.g. 'orbitals.xsf'): ").strip()
|
|
313
|
+
if not filename:
|
|
314
|
+
filename = "orbitals.xsf"
|
|
315
|
+
|
|
316
|
+
# Initialize orbital file
|
|
317
|
+
orbital_file = OrbitalFile(filename)
|
|
318
|
+
|
|
319
|
+
print("\nSupported orbitals are:")
|
|
320
|
+
print("s, p_z, p_x, p_y")
|
|
321
|
+
print(f"{' '.join(map(str, d_orbitals))}")
|
|
322
|
+
print(f"{' '.join(map(str, f_orbitals))}")
|
|
323
|
+
|
|
324
|
+
print("\nEnter orbital data in format: Element orbital [x y z]")
|
|
325
|
+
print("\nExample: 'O p_z 0 0 1' or 'Fe d_{xy}'")
|
|
326
|
+
print("Type 'done' to finish and generate visualization")
|
|
327
|
+
|
|
328
|
+
while True:
|
|
329
|
+
try:
|
|
330
|
+
# Get user input
|
|
331
|
+
user_input = input("\nEnter orbital data: ").strip()
|
|
332
|
+
|
|
333
|
+
# Check for exit condition
|
|
334
|
+
if user_input.lower() == 'done':
|
|
335
|
+
break
|
|
336
|
+
|
|
337
|
+
# Parse input
|
|
338
|
+
parts = user_input.split()
|
|
339
|
+
if len(parts) < 2:
|
|
340
|
+
print("Error: Please provide at least element and orbital type")
|
|
341
|
+
continue
|
|
342
|
+
|
|
343
|
+
element = parts[0]
|
|
344
|
+
orbital_type = parts[1]
|
|
345
|
+
|
|
346
|
+
if orbital_type not in supported_orbitals:
|
|
347
|
+
print(f"Error: Unsupported orbital type '{orbital_type}'")
|
|
348
|
+
continue
|
|
349
|
+
|
|
350
|
+
# Parse position if provided
|
|
351
|
+
if len(parts) == 5:
|
|
352
|
+
try:
|
|
353
|
+
position = [float(parts[2]), float(parts[3]), float(parts[4])]
|
|
354
|
+
except ValueError:
|
|
355
|
+
print("Error: Position coordinates must be numbers")
|
|
356
|
+
continue
|
|
357
|
+
else:
|
|
358
|
+
position = [0.0, 0.0, 0.0]
|
|
359
|
+
|
|
360
|
+
# Get atomic number
|
|
361
|
+
try:
|
|
362
|
+
z_number = get_atomic_number(element)
|
|
363
|
+
except KeyError:
|
|
364
|
+
print(f"Error: Unknown element '{element}'")
|
|
365
|
+
continue
|
|
366
|
+
|
|
367
|
+
# Add orbital
|
|
368
|
+
orbital_file.add_orbital(
|
|
369
|
+
orbital=orbital_type,
|
|
370
|
+
position=position,
|
|
371
|
+
znumber=z_number,
|
|
372
|
+
coeff=1.0
|
|
373
|
+
)
|
|
374
|
+
print(f"Added {orbital_type} orbital for {element} at position {position}")
|
|
375
|
+
|
|
376
|
+
except KeyboardInterrupt:
|
|
377
|
+
print("\nOperation cancelled by user")
|
|
378
|
+
return
|
|
379
|
+
except Exception as e:
|
|
380
|
+
print(f"Error: {str(e)}")
|
|
381
|
+
continue
|
|
382
|
+
|
|
383
|
+
try:
|
|
384
|
+
print("\nGenerating visualization...")
|
|
385
|
+
orbital_file.write_data(squared=False)
|
|
386
|
+
print("\nDone! You can now visualize the orbitals using XCrySDen, VESTA or similar software.")
|
|
387
|
+
except Exception as e:
|
|
388
|
+
print(f"Error while generating visualization: {str(e)}")
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
if __name__ == "__main__":
|
|
392
|
+
main()
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Dmitry Korotin dmitry@korotin.name
|
|
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,106 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: atorvi
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Package for visualizing atomic orbitals
|
|
5
|
+
Author-email: Dmitry Korotin <dmitry@korotin.name>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/dkorotin/atorvi
|
|
8
|
+
Keywords: atomic orbitals,visualization
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Requires-Python: >=3.6
|
|
13
|
+
Description-Content-Type: text/markdown
|
|
14
|
+
License-File: LICENSE
|
|
15
|
+
Requires-Dist: numpy
|
|
16
|
+
Requires-Dist: scipy
|
|
17
|
+
Provides-Extra: pymatgen
|
|
18
|
+
Requires-Dist: pymatgen; extra == "pymatgen"
|
|
19
|
+
|
|
20
|
+
# atorvi - ATomic ORbitals VIsualization
|
|
21
|
+
|
|
22
|
+

|
|
23
|
+
|
|
24
|
+
**atorvi** is a Python package for visualizing individual atomic orbitals and their various linear combinations. The library generates requested atomic orbitals on a 3D mesh and exports them, along with the inputted crystal structure (molecule or periodic crystal), into a file in [XCrysDen .xsf format](http://www.xcrysden.org/doc/XSF.html).
|
|
25
|
+
|
|
26
|
+
The resulting `.xsf` file can be opened and visualized using your favorite visualization software, such as [XCrysDen](http://www.xcrysden.org/), [VESTA](https://jp-minerals.org/vesta/en/) or [VMD](https://www.ks.uiuc.edu/Research/vmd/).
|
|
27
|
+
|
|
28
|
+
## Installation
|
|
29
|
+
|
|
30
|
+
To install **atorvi**, you can use `pip`:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
pip install atorvi
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Features
|
|
37
|
+
|
|
38
|
+
- **Atomic Orbitals Generation**: Create atomic orbitals at a specific position in space or at a designated atom/element within a crystal structure.
|
|
39
|
+
|
|
40
|
+
- **Flexible Structure Input**: Input crystal structures either manually, atom-by-atom, or directly from standard file formats such as POSCAR, XSF, CIF, and more. The integration with the `pymatgen` package simplifies structure handling.
|
|
41
|
+
|
|
42
|
+
- **Orbital Hybridization**: Implement orbital hybridization by mixing different orbitals with custom coefficients, allowing for the exploration of complex bonding interactions.
|
|
43
|
+
|
|
44
|
+
- **Orbital Squared Moduli**: Generate squared moduli of orbitals, providing insight into their spatial distribution and probability densities.
|
|
45
|
+
|
|
46
|
+
Examples of orbitals generated with **atorvi**: could be found in [examples](./examples/) folder.
|
|
47
|
+
|
|
48
|
+
## Quick start
|
|
49
|
+
|
|
50
|
+
The full user manual is available in [docs/atorvi_manual.md](./docs/atorvi_manual.md).
|
|
51
|
+
|
|
52
|
+
**atorvi** can be used in two modes: package mode (for scripting and notebooks) and CLI interactive mode (only basic functionality is available).
|
|
53
|
+
|
|
54
|
+
### 1.Package Mode
|
|
55
|
+
In your Python script or Jupyter notebook, you can generate and visualize atomic orbitals with the following example:
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
import atorvi
|
|
59
|
+
|
|
60
|
+
# Example: visualize a d_{3z^2-r^2} orbital for an Ni atom (Z = 28)
|
|
61
|
+
outfile = atorvi.OrbitalFile("Ni_orbital.xsf")
|
|
62
|
+
|
|
63
|
+
outfile.add_orbital("d_{3z^2-r^2}", position=[0, 0, 0], znumber=28)
|
|
64
|
+
|
|
65
|
+
outfile.write_data()
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Then just open the `Ni_orbital.xsf` file in your favorite visualization software.
|
|
69
|
+
|
|
70
|
+
The orbitals available for generation are:
|
|
71
|
+
$$s$$
|
|
72
|
+
$$p_z, p_x, p_y$$
|
|
73
|
+
$$d_{3z^2-r^2}, d_{xz}, d_{yz}, d_{xy}, d_{x^2-y^2} $$
|
|
74
|
+
$$f_{z^3}, f_{xz^2}, f_{yz^2}, f_{xyz}, f_{z(x^2-y^2)}, f_{x(x^2-3y^2)}, f_{y(3x^2-y^2)}$$
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
print(atorvi.supported_orbitals)
|
|
78
|
+
|
|
79
|
+
['s',
|
|
80
|
+
'p_z', 'p_x', 'p_y',
|
|
81
|
+
'd_{3z^2-r^2}', 'd_{xz}', 'd_{yz}', 'd_{xy}', 'd_{x^2-y^2}',
|
|
82
|
+
'f_{z^3}', 'f_{xz^2}', 'f_{yz^2}', 'f_{xyz}', 'f_{z(x^2-y^2)}', 'f_{x(x^2-3y^2)}', 'f_{y(3x^2-y^2)}']
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 2. CLI Interactive Mode
|
|
86
|
+
atorvi also offers an interactive mode via the command line interface (CLI). You can simply run the script directly in a terminal:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
atorvi_cli
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Follow the prompts to generate orbitals and export them to XCrysDen-compatible formats.
|
|
93
|
+
|
|
94
|
+
Once the file is generated, you can open it using visualization tools like XCrysDen or VESTA.
|
|
95
|
+
|
|
96
|
+
## Author
|
|
97
|
+
|
|
98
|
+
`atorvi` is developed and maintained by [Dmitry Korotin](https://www.researchgate.net/profile/Dmitry-Korotin). Contributions, suggestions, and feedback are welcome to help improve the project.
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
`atorvi` is released under the MIT License. You are free to use, modify, and distribute the software, provided that the original copyright and permission notice are included in all copies or substantial portions of the software.
|
|
103
|
+
|
|
104
|
+
The author kindly asks that you cite this GitHub repository [github.com/dkorotin/atorvi](https://github.com/dkorotin/atorvi) and the related paper (link will be available soon) in any publications that use images or data generated with the `atorvi` package.
|
|
105
|
+
|
|
106
|
+
For more details, refer to the full [MIT License](./LICENSE).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
atorvi/__init__.py,sha256=MfCiHbcrEQ4aaVvCvW2z132FSvJP0x8axN99rhan-ok,754
|
|
2
|
+
atorvi/atomic_orbitals.py,sha256=aUWciftqq9XxGGJ8Z6c5MJTvLskZnRFN0PpfVhqn5gI,20291
|
|
3
|
+
atorvi/atorvi.py,sha256=1KHzWxxk-hZ-UxjYBksnT0LN-8_9ojdTNMSj7pi9HwI,12594
|
|
4
|
+
atorvi-0.1.1.dist-info/LICENSE,sha256=II7eEoRanRl9pcHPqcHDvaC6_jhL5OnFzpQQCYAwMw8,1090
|
|
5
|
+
atorvi-0.1.1.dist-info/METADATA,sha256=sq1SZnssHA4kBpPET4bchZK1UvxggdC_FxEgmEenNfs,4517
|
|
6
|
+
atorvi-0.1.1.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
|
7
|
+
atorvi-0.1.1.dist-info/entry_points.txt,sha256=rnPj_hrqVhtwpJEP_28sStjyYbLKOIdzykH2y9LCL5Q,43
|
|
8
|
+
atorvi-0.1.1.dist-info/top_level.txt,sha256=u6MN9V2sONM4ZqwOiSrsE6DKvDO1JJf--RzWWgEWe2k,7
|
|
9
|
+
atorvi-0.1.1.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
atorvi
|