mdkits 0.1a1__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.

Potentially problematic release.


This version of mdkits might be problematic. Click here for more details.

@@ -0,0 +1,46 @@
1
+ """
2
+ filename: cp2k_input_parsing.py
3
+ function: prase cp2k file
4
+ """
5
+
6
+
7
+ import sys
8
+
9
+
10
+ def parse_cell(cp2k_input_file):
11
+ """
12
+ function: parse cell information from cp2k input file
13
+ parameter:
14
+ cp2k_input_file: filename of cp2k input
15
+ return:
16
+ cell: list with 6 number
17
+ """
18
+ try:
19
+ with open(cp2k_input_file, 'r') as f:
20
+ cell = []
21
+ for line in f:
22
+ if "ABC" in line:
23
+ xyz = line.split()[-3:]
24
+ cell.extend(xyz)
25
+ if "ALPHA_BETA_GAMMA" in line:
26
+ abc = line.split()[-3:]
27
+ cell.extend(abc)
28
+ if len(cell) == 3:
29
+ cell.extend([90.0, 90.0, 90.0])
30
+
31
+ print(f"system cell: x = {cell[0]}, y = {cell[1]}, z = {cell[2]}, a = {cell[3]}\u00B0, b = {cell[4]}\u00B0, c = {cell[5]}\u00B0")
32
+ return cell
33
+ except FileNotFoundError:
34
+ print(f'cp2k input file name "{cp2k_input_file}" is not found, assign a cp2k input file or assign a "cell"')
35
+ sys.exit(1)
36
+
37
+
38
+ #def get_cell(cp2k_input_file, cell=None):
39
+ # if cell is None:
40
+ # cell = parse_cell(cp2k_input_file)
41
+ # else:
42
+ # cell = cell
43
+ # if len(cell) == 3:
44
+ # cell.extend([90.0, 90.0, 90.0])
45
+ #
46
+ # return cell
@@ -0,0 +1,134 @@
1
+ """
2
+ filename: encapsulated_ase.py
3
+ function: some encapsulated ase method
4
+ """
5
+
6
+
7
+ from ase.io import iread, read
8
+ import io
9
+ import numpy as np
10
+ from ase.io.cube import read_cube_data
11
+
12
+
13
+ def wrap_to_cell(chunk, cell, name, big=False):
14
+ """
15
+ function: encapsulated ase.Atom.wrap method
16
+ parameter:
17
+ chunk: a list of frame of structure
18
+ cell: a list of cell parameter
19
+ name: path of temp file to write
20
+ big: make 3X3X1 supercell
21
+ return:
22
+ write into a temp file
23
+ """
24
+ # wrap a chunk of .xyz sturcture in a cell, and write wraped structure to file
25
+ if len(chunk) > 1:
26
+ atoms = iread(io.StringIO('\n'.join(chunk)), format='xyz')
27
+ else:
28
+ atoms = iread(chunk, format='xyz')
29
+ with open(name, 'w') as f:
30
+ f.write('')
31
+ for atom in atoms:
32
+ atom.set_cell(cell)
33
+ atom.set_pbc(True)
34
+ atom.wrap()
35
+ if big:
36
+ from ase.build import make_supercell
37
+ P = [ [3, 0, 0], [0, 3, 0], [0, 0, 1] ]
38
+ atom = make_supercell(atom, P)
39
+ atom.write(f'{name}', append='a', format='xyz')
40
+
41
+
42
+ def rdf(chunk, cell, bin_size, name, parallel=True):
43
+ """
44
+ not used
45
+ """
46
+ from ase.geometry.analysis import Analysis
47
+ from math import ceil
48
+ n = ceil(cell[2] / bin_size)
49
+ if parallel:
50
+ atoms = iread(io.StringIO('\n'.join(chunk)), format='xyz')
51
+ else:
52
+ atoms = iread(chunk, format='xyz')
53
+ atom_list = []
54
+ for atom in atoms:
55
+ atom.set_cell(cell)
56
+ atom.set_pbc(True)
57
+ atom_list.append(atom)
58
+ print(len(atom_list))
59
+ ana = Analysis(atom_list)
60
+ rdf = ana.get_rdf(3.5, n, elements=['O'])
61
+ rdf_array = np.vstack(rdf)
62
+ rdf_array = np.mean(rdf_array, axis=0)
63
+ print(name)
64
+ np.save(name, rdf_array)
65
+ ana.clear_cache()
66
+
67
+
68
+ def ave_potential(filepath):
69
+ """
70
+ function: average hartree file in z_coordinate
71
+ parameter:
72
+ filepath: hartree cube file path
73
+ return:
74
+ z_potential: a list of potential alone z axes
75
+ z_coordinates: a list of coordinates of z axes
76
+ """
77
+ # read data from filepath
78
+ data, atoms = read_cube_data(filepath)
79
+ # define need parameter
80
+ npoints = data.shape[2]
81
+ step_size = atoms.cell[2, 2] / ( npoints - 1 )
82
+ # average hartree file, and calculate z_coordinates
83
+ z_coordinates = [i * step_size for i in range(npoints)]
84
+ z_potential = 27.2114 * data[:, :, :].sum(axis=(0, 1)) / ( data.shape[0] * data.shape[1] )
85
+ return z_potential, z_coordinates
86
+
87
+
88
+ def atoms_read_with_cell(file_name, cell=None, coord_mode=False, default_cell=np.array([0., 0., 0., 90., 90., 90.])):
89
+ """
90
+ function: read structure file return a Atoms object with cell
91
+ parameter:
92
+ file_name: structure file name
93
+ cell: cell list
94
+ coord_mode: if file name is coord format
95
+ default_cell: default cell of Atoms object
96
+ return:
97
+ atoms: Atoms object with cell
98
+ """
99
+ import sys, os
100
+ from . import cp2k_input_parsing, structure_parsing
101
+
102
+ if coord_mode:
103
+ xyz = structure_parsing.coord_to_xyz(file_name)
104
+ atoms = read(io.StringIO('\n'.join(xyz)), format='xyz')
105
+ else:
106
+ atoms = jread(file_name)
107
+
108
+ if cell == None:
109
+ cp2k_cell_file_name = ( 'cell.inc', 'setup.inp', 'input.inp' )
110
+ existing_cell_file = [ file for file in cp2k_cell_file_name if os.path.isfile(file) ]
111
+ if existing_cell_file:
112
+ cell = cp2k_input_parsing.parse_cell(existing_cell_file[0])
113
+
114
+ if np.array_equal(atoms.cell.cellpar(), default_cell):
115
+ if cell != None:
116
+ atoms.set_cell(cell)
117
+ print('cell: \n' + ', '.join(map(str, atoms.cell.cellpar())))
118
+ return atoms
119
+ else:
120
+ print("no cell")
121
+ sys.exit(1)
122
+ print('cell: \n' + ', '.join(map(str, atoms.cell.cellpar())))
123
+ return atoms
124
+
125
+
126
+ def jread(filepath):
127
+ from ase.io import read
128
+ suffix = filepath.split('.')[-1]
129
+ if suffix == 'data':
130
+ atom = read(filepath, format='lammps-data', atom_style='atomic')
131
+ else:
132
+ atom = read(filepath)
133
+
134
+ return atom
@@ -0,0 +1,59 @@
1
+ import MDAnalysis
2
+ import numpy as np
3
+ from . import numpy_geo
4
+
5
+
6
+ def update_water(self, o_group, h_group, distance_judg=1.2, angle_judg:tuple[float, float]=None, return_index=False):
7
+ """
8
+ input: o and h atom
9
+ output: o and two h in this frame
10
+ """
11
+ oh_pair = MDAnalysis.lib.distances.capped_distance(o_group.positions, h_group.positions, min_cutoff=0, max_cutoff=distance_judg, box=self.u.dimensions, return_distances=False)
12
+
13
+ oh_o = oh_pair[:, 0]
14
+ unique_oh_o = np.unique(oh_o)
15
+
16
+ group_oh_h = {}
17
+ for oh_o_index in unique_oh_o:
18
+ oh_h_index = oh_pair[oh_o == oh_o_index, 1]
19
+ group_oh_h[oh_o_index] = oh_h_index
20
+
21
+ oh1_list = []
22
+ oh2_list = []
23
+ o_list = []
24
+ for oh_o_index in unique_oh_o:
25
+ oh_h_index = group_oh_h[oh_o_index]
26
+ if angle_judg is not None and len(oh_h_index) >= 2:
27
+ for i in range(len(oh_h_index)):
28
+ for j in range(i + 1, len(oh_h_index)):
29
+ h1_index = oh_h_index[i]
30
+ h2_index = oh_h_index[j]
31
+
32
+ o_pos = o_group[oh_o_index].position
33
+ h1_pos = h_group[h1_index].position
34
+ h2_pos = h_group[h2_index].position
35
+
36
+ oh1_vec = h1_pos - o_pos
37
+ oh2_vec = h2_pos - o_pos
38
+
39
+ angle_deg = numpy_geo.vector_vector_angle(oh1_vec, oh2_vec)
40
+
41
+ if angle_judg[0] <= angle_deg <= angle_judg[1]:
42
+ o_list.append(oh_o_index)
43
+ oh1_list.append(h1_index)
44
+ oh2_list.append(h2_index)
45
+ elif len(oh_h_index) == 2:
46
+ o_list.append(oh_o_index)
47
+ oh1_list.append(oh_h_index[0])
48
+ oh2_list.append(oh_h_index[1])
49
+ oh1_index = np.array(oh1_list)
50
+ oh2_index = np.array(oh2_list)
51
+ o_index = np.array(o_list)
52
+
53
+ if return_index:
54
+ return o_index, oh1_index, oh2_index
55
+ else:
56
+ o = o_group[o_index]
57
+ oh1 = h_group[oh1_index]
58
+ oh2 = h_group[oh2_index]
59
+ return o, oh1, oh2
@@ -0,0 +1,28 @@
1
+ import os
2
+ import matplotlib.pyplot as plt
3
+
4
+
5
+ def savefig(fig, name, fold=None):
6
+ current_path = os.getcwd()
7
+ if fold:
8
+ if not os.path.exists(fold):
9
+ os.mkdir(fold)
10
+ fig.savefig(f"{current_path}/{fold}/{name}.png", format='png')
11
+ vector_fig_dir = f'pdf'
12
+ if not os.path.exists(vector_fig_dir):
13
+ os.mkdir(vector_fig_dir)
14
+ vector_fig_dir = f'pdf/{fold}'
15
+ if not os.path.exists(vector_fig_dir):
16
+ os.mkdir(vector_fig_dir)
17
+ fig.savefig(f"{current_path}/{vector_fig_dir}/{name}.pdf", format='pdf', transparent=True)
18
+ else:
19
+ fig.savefig(f"{current_path}/{name}.png", format='png')
20
+ vector_fig_dir = f'pdf'
21
+ if not os.path.exists(vector_fig_dir):
22
+ os.mkdir(vector_fig_dir)
23
+ fig.savefig(f"{current_path}/{vector_fig_dir}/{name}.pdf", format='pdf', transparent=True)
24
+
25
+
26
+ def scaled_figsize(scale_w=1.0, scale_h=1.0):
27
+ default_size = plt.rcParams["figure.figsize"]
28
+ return [default_size[0]*scale_w, default_size[1]*scale_h]
@@ -0,0 +1,118 @@
1
+ """
2
+ filename: numpy_geo.py
3
+ function: some vector calculation with numpy
4
+ """
5
+
6
+
7
+ from numpy import array, dot, abs, cross
8
+ from numpy.linalg import norm
9
+ import numpy as np
10
+
11
+
12
+
13
+ def point_plane_distance(plane):
14
+ # distance of point with a plane(a list with [normal_voctor, a_point_in_plane])
15
+ def point(point):
16
+ return abs(dot(plane[0], point - plane[1])) / norm(plane[0])
17
+ return point
18
+
19
+
20
+ def point_point_distance(point1, point2):
21
+ # distance of point with a point
22
+ return norm(point1 - point2)
23
+
24
+
25
+ def point(frame):
26
+ # return a point of atom, from .xyz file
27
+ def point_index(index):
28
+ return array(frame[index].split()[1:]).astype(float)
29
+ return point_index
30
+
31
+ def plane(frame, index1, index2, index3):
32
+ # return a normal voctor of a plane with three point(index and group)
33
+ get_point = point(frame)
34
+ base1 = get_point(index1)
35
+ base2 = get_point(index2)
36
+ base3 = get_point(index3)
37
+ return [cross(base2 - base1, base3 - base1), base3]
38
+
39
+
40
+ def vector_between_two_vector(vector1, vector2):
41
+ vector1_unit = vector1 / np.linalg.norm(vector1)
42
+ vector2_unit = vector2 / np.linalg.norm(vector2)
43
+ vector = vector1_unit + vector2_unit
44
+ return vector
45
+
46
+
47
+ def vector_vector_angle(vector, surface_vector):
48
+ cos = np.dot(vector, surface_vector) / (np.linalg.norm(vector) * np.linalg.norm(surface_vector))
49
+ vector_vector_angle = np.arccos(np.clip(cos, -1.0, 1.0))
50
+ vector_vector_angle = np.degrees(vector_vector_angle)
51
+ return vector_vector_angle
52
+
53
+
54
+ def cell_to_wrap_coefficients(cell, z=False):
55
+ angle = np.radians(180-cell[-1])
56
+ dangle = [np.cos(angle), np.sin(angle)]
57
+ xyz = cell[0:3]
58
+ if z:
59
+ coefficients = np.array([
60
+ [(kx * xyz[0] + ky * dangle[0] * xyz[1]), (ky * dangle[1] * xyz[1]), kz * xyz[2]]
61
+ for kx in range(-1, 2)
62
+ for ky in range(-1, 2)
63
+ for kz in range(-1, 2)
64
+ ])
65
+ else:
66
+ coefficients = np.array([
67
+ [(kx * xyz[0] + ky * dangle[0] * xyz[1]), (ky * dangle[1] * xyz[1]), 0]
68
+ for kx in range(-1, 2)
69
+ for ky in range(-1, 2)
70
+ ])
71
+
72
+ return coefficients
73
+
74
+
75
+ def unwrap(atom1, atom2, coefficients, max=0, total=False):
76
+ init_dist = point_point_distance(atom1, atom2)
77
+ if total:
78
+ atoms = atom2 + coefficients
79
+ distance = np.linalg.norm(atoms-atom1, axis=1)
80
+
81
+ return distance, atoms
82
+ else:
83
+ if init_dist > max:
84
+ min_dist = float('inf')
85
+ closest_point = None
86
+ atoms = atom2 + coefficients
87
+ distance = np.linalg.norm(atoms-atom1, axis=1)
88
+ min_index = np.argmin(distance)
89
+ min_dist = distance[min_index]
90
+ closest_point = atoms[min_index]
91
+
92
+ else:
93
+ closest_point = atom2
94
+ min_dist = init_dist
95
+
96
+ return min_dist, closest_point
97
+
98
+
99
+ def find_surface(surface_group:np.ndarray, layer_tolerance=1, surface_tolerance=5):
100
+ sort_group = surface_group.sort()
101
+ layer_mean = []
102
+ current_layer = [sort_group[0]]
103
+ for i in range(1, len(sort_group)):
104
+ if abs(sort_group[i] - sort_group[i-1]) < layer_tolerance:
105
+ current_layer.append(sort_group[i])
106
+ else:
107
+ layer_mean.append(np.mean(current_layer))
108
+ current_layer = [sort_group[i]]
109
+
110
+ if len(current_layer) == 1:
111
+ return layer_mean[0]
112
+
113
+ diff = np.diff(layer_mean)
114
+ if np.any(diff > surface_tolerance):
115
+ index = np.argmax(diff > 5)
116
+ return (layer_mean[index], layer_mean[index + 1])
117
+ else:
118
+ return layer_mean[-1]
@@ -0,0 +1,35 @@
1
+ import os, shutil, atexit
2
+
3
+
4
+ def make_temp_dir(temp_dir, delete=False):
5
+ if os.path.exists(temp_dir):
6
+ shutil.rmtree(temp_dir)
7
+ os.mkdir(temp_dir)
8
+ if delete:
9
+ atexit.register(remove_temp_dir, temp_dir)
10
+
11
+
12
+ def remove_temp_dir(temp_dir):
13
+ shutil.rmtree(temp_dir)
14
+
15
+
16
+ def default_file_name(match, last=False):
17
+ import glob
18
+ file_list = glob.glob(match)
19
+ if file_list:
20
+ if last:
21
+ default_file_name = sort_word_and_number(file_list)[-1]
22
+ else:
23
+ default_file_name = list(file_list)
24
+ else:
25
+ default_file_name = None
26
+
27
+ return default_file_name
28
+
29
+
30
+ def sort_word_and_number(unsort_list):
31
+ import re
32
+ fns = lambda s: sum(((s,int(n))for s,n in re.findall('(\D+)(\d+)','a%s0'%s)),())
33
+ sorted_list = sorted(unsort_list, key=fns)
34
+
35
+ return sorted_list
@@ -0,0 +1,147 @@
1
+ """
2
+ filename: structure_parsing.py
3
+ function: prase file with .xyz structue
4
+ """
5
+
6
+
7
+ import numpy as np
8
+
9
+
10
+ def xyz_to_chunks(filename, thread):
11
+ """
12
+ function: split .xyz file to chunks to parallel analysis
13
+ """
14
+ with open(filename, 'r') as f:
15
+ data = f.read()
16
+
17
+ #with open(filename, 'r') as f:
18
+ # atom_number = int(f.readline().split()[0]) + 2
19
+
20
+ atom_number = int(data[:data.index('\n') + 1]) + 2
21
+ line_data = data.split('\n')
22
+ chunk_size = (len(line_data) / atom_number) // thread
23
+ chunks = [line_data[i:i+int(chunk_size*atom_number)] for i in range(0, len(line_data), int(chunk_size*atom_number))]
24
+ return chunks
25
+
26
+
27
+ def xyz_to_groups(filename, cut=0):
28
+ """
29
+ function: split .xyz file to groups, every groups is one single frame
30
+ """
31
+ with open(filename, 'r') as f:
32
+ data = f.read()
33
+
34
+ # read number of atoms
35
+ end_index = data.index('\n') + 1
36
+ natom = int(data[:end_index]) + 2
37
+
38
+ # seqrate file with natom +2
39
+ lines = data.split('\n')
40
+ groups = [lines[i+cut:i+natom] for i in range(0, len(lines), natom)][:-1]
41
+ return groups
42
+
43
+
44
+ def xyz_to_specified_list(filename, atom_range, cut=0):
45
+ """
46
+ function: split .xyz file to specified list, specified atoms position list
47
+ """
48
+ with open(filename, 'r') as f:
49
+ data = f.read()
50
+
51
+ # read number of atoms
52
+ end_index = data.index('\n') + 1
53
+ natom = int(data[:end_index]) + 2
54
+
55
+ # seqrate file with natom +2
56
+ lines = data.split('\n')
57
+ if len(atom_range) > 1:
58
+ groups = [lines[i+atom_range[0]:i+atom_range[1]] for i in range(0, len(lines), natom)][:-1]
59
+ else:
60
+ groups = [lines[i+atom_range[0]] for i in range(0, len(lines), natom)][:-1]
61
+ return groups
62
+
63
+
64
+ def xyz_to_specified_array(filename, atom_range, cut=0):
65
+ """
66
+ function: split .xyz file to specified list, specified atoms position list
67
+ """
68
+ with open(filename, 'r') as f:
69
+ data = f.read()
70
+
71
+ # read number of atoms
72
+ end_index = data.index('\n') + 1
73
+ natom = int(data[:end_index]) + 2
74
+
75
+ # seqrate file with natom +2
76
+ lines = data.split('\n')
77
+ if len(atom_range) > 1:
78
+ groups = [lines[i+atom_range[0]:i+atom_range[1]] for i in range(0, len(lines), natom)][:-1]
79
+ else:
80
+ groups = [lines[i+atom_range[0]] for i in range(0, len(lines), natom)][:-1]
81
+ groups = [groups[i][j].split()[1:] for i in range(len(groups)) for j in range(len(groups[i]))]
82
+ return np.array(groups, dtype=np.float64)
83
+
84
+
85
+ def xyz_to_npy(filename):
86
+ """
87
+ function: parse .xyz file to numpy array with float dtype, and cut first column of atom type
88
+ """
89
+ data = xyz_to_groups(filename, cut=2)
90
+ new_data = [[list(map(float, subsublist.split()[1:])) for subsublist in sublist] for sublist in data]
91
+ return np.array(new_data)
92
+
93
+
94
+ def chunk_to_groups(data):
95
+ """
96
+ function: split chunk to single frames
97
+ """
98
+ natom = int(data[0]) + 2
99
+ groups = [data[i:i+natom] for i in range(0, len(data), natom)][:-1]
100
+ return groups
101
+
102
+
103
+ def groups_to_xyz(filename, groups, cut=None):
104
+ """
105
+ function: write groups(some of frame) to .xyz file
106
+ """
107
+ with open(filename, 'w') as f:
108
+ for group in groups:
109
+ for i in group[cut:]:
110
+ f.write(i + '\n')
111
+
112
+
113
+ def group_to_xyz(filename, group, cut=None):
114
+ """
115
+ function: write groups(some of frame) to .xyz file
116
+ """
117
+ with open(filename, 'w') as f:
118
+ for i in group[cut:]:
119
+ f.write(i + '\n')
120
+
121
+
122
+ def coord_to_xyz(filename):
123
+ with open(filename, 'r') as f:
124
+ data = f.read()
125
+ data = data.split('\n')
126
+ data.insert(0, '')
127
+ data.insert(0, str(len(data)-2))
128
+ return data
129
+
130
+
131
+ def atom_mass_parse(group):
132
+ import periodictable
133
+ atom_mass_dict = {}
134
+ names = atom_name_parse()
135
+ for name in names:
136
+ if hasattr(periodictable, name):
137
+ atom = getattr(periodictable, name)
138
+ atom_mass_dict[name] = atom.mass
139
+ else:
140
+ print(f'dont have face named {name}, use mass is 0')
141
+ atom_mass_dict[name] = 0
142
+ return atom_mass_dict
143
+
144
+
145
+ def atom_name_parse(group):
146
+ names = {row.split()[0] for row in group[2:]}
147
+ return names
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 jxxcr
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.