mlatom 2.0.0__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.
- MLatom/ML_NEA.py +2697 -0
- MLatom/MLatom.py +151 -0
- MLatom/MLatomF +0 -0
- MLatom/MLtasks.py +767 -0
- MLatom/__init__.py +0 -0
- MLatom/args_class.py +396 -0
- MLatom/cs.so +0 -0
- MLatom/doc.py +620 -0
- MLatom/header.py +64 -0
- MLatom/interface_MLatomF.py +87 -0
- MLatom/interfaces/DeePMDkit/DP_inference.py +20 -0
- MLatom/interfaces/DeePMDkit/__init__.py +0 -0
- MLatom/interfaces/DeePMDkit/interface_DeePMDkit.py +327 -0
- MLatom/interfaces/DeePMDkit/template.json +70 -0
- MLatom/interfaces/GAP/__init__.py +0 -0
- MLatom/interfaces/GAP/interface_GAP.py +415 -0
- MLatom/interfaces/PhysNet/PhysNet_predict.py +180 -0
- MLatom/interfaces/PhysNet/PhysNet_train.py +425 -0
- MLatom/interfaces/PhysNet/__init__.py +0 -0
- MLatom/interfaces/PhysNet/interface_PhysNet.py +270 -0
- MLatom/interfaces/TorchANI/TorchANI_predict.py +82 -0
- MLatom/interfaces/TorchANI/TorchANI_train.py +217 -0
- MLatom/interfaces/TorchANI/__init__.py +0 -0
- MLatom/interfaces/TorchANI/interface_TorchANI.py +323 -0
- MLatom/interfaces/__init__.py +0 -0
- MLatom/interfaces/sGDML/__init__.py +0 -0
- MLatom/interfaces/sGDML/interface_sGDML.py +276 -0
- MLatom/interfaces/sGDML/sgdml_dataset_from_extxyz.py +199 -0
- MLatom/ref.json +23 -0
- MLatom/sliceData.py +334 -0
- MLatom/stopper.py +17 -0
- MLatom-2.0.0.data/scripts/MLatomF +12 -0
- MLatom-2.0.0.data/scripts/mlatom +12 -0
- MLatom-2.0.0.dist-info/LICENSE.txt +251 -0
- MLatom-2.0.0.dist-info/METADATA +149 -0
- MLatom-2.0.0.dist-info/RECORD +38 -0
- MLatom-2.0.0.dist-info/WHEEL +5 -0
- MLatom-2.0.0.dist-info/top_level.txt +1 -0
MLatom/__init__.py
ADDED
|
File without changes
|
MLatom/args_class.py
ADDED
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
'''
|
|
3
|
+
!---------------------------------------------------------------------------!
|
|
4
|
+
! args_class: handling input of MLatom !
|
|
5
|
+
! Implementations by: Bao-Xin Xue !
|
|
6
|
+
!---------------------------------------------------------------------------!
|
|
7
|
+
'''
|
|
8
|
+
|
|
9
|
+
from collections import defaultdict, UserDict
|
|
10
|
+
from os import replace
|
|
11
|
+
from typing import Callable, DefaultDict, Sequence, Tuple, Union
|
|
12
|
+
from typing import List, Tuple, Dict, Set, Any
|
|
13
|
+
from copy import copy
|
|
14
|
+
import re
|
|
15
|
+
import stopper
|
|
16
|
+
|
|
17
|
+
try:
|
|
18
|
+
from doc import Doc
|
|
19
|
+
except:
|
|
20
|
+
Doc = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class KeyNotFoundException(Exception):
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class DuplicatedKeyException(Exception):
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class AttributeDict(UserDict):
|
|
32
|
+
data: Dict[Any, Any]
|
|
33
|
+
lower_key_set: Set[Any]
|
|
34
|
+
lower_key_to_key: Dict[str, str]
|
|
35
|
+
attribute_dict_variable = ['data', 'lower_key_set', 'lower_key_to_key', 'attribute_dict_variable']
|
|
36
|
+
|
|
37
|
+
def __init__(self) -> None:
|
|
38
|
+
self.__dict__['data'] = {}
|
|
39
|
+
self.__dict__['lower_key_set'] = set()
|
|
40
|
+
self.__dict__['lower_key_to_key'] = {}
|
|
41
|
+
self.__dict__['writable_flag'] = False
|
|
42
|
+
|
|
43
|
+
@classmethod
|
|
44
|
+
def merge_dict(cls, my_dict: 'AttributeDict', other: Dict[str, Any]) -> None:
|
|
45
|
+
for other_key in other.keys():
|
|
46
|
+
other_key_strip = other_key.strip() # for the usage of my_dict
|
|
47
|
+
other_key_lower = other_key_strip.lower() # for the usage of my_dict.lower_key_set
|
|
48
|
+
if other_key_lower in my_dict.lower_key_set:
|
|
49
|
+
if type(other[other_key]) in [dict, cls]:
|
|
50
|
+
if type(my_dict[other_key_strip]) is not cls:
|
|
51
|
+
my_dict[other_key_strip] = AttributeDict()
|
|
52
|
+
cls.merge_dict(my_dict[other_key_strip], other[other_key])
|
|
53
|
+
else:
|
|
54
|
+
my_dict[other_key_strip] = other[other_key]
|
|
55
|
+
else:
|
|
56
|
+
my_dict.lower_key_set.add(other_key_lower)
|
|
57
|
+
my_dict.lower_key_to_key[other_key_lower] = other_key_strip
|
|
58
|
+
my_dict[other_key_strip] = other[other_key]
|
|
59
|
+
|
|
60
|
+
def key_in_dict(self, name: str) -> bool:
|
|
61
|
+
lower_key = name.lower().strip()
|
|
62
|
+
return lower_key in self.lower_key_set
|
|
63
|
+
|
|
64
|
+
@classmethod
|
|
65
|
+
def dict_to_attributedict(cls, d: Dict[str, Any]) -> 'AttributeDict':
|
|
66
|
+
new_dict = cls()
|
|
67
|
+
for key, value in d.items():
|
|
68
|
+
if type(value) is dict:
|
|
69
|
+
new_value = cls.dict_to_attributedict(value)
|
|
70
|
+
new_dict[key] = new_value
|
|
71
|
+
else:
|
|
72
|
+
new_dict[key] = value
|
|
73
|
+
return new_dict
|
|
74
|
+
|
|
75
|
+
@classmethod
|
|
76
|
+
def normal_dict(cls, d: 'AttributeDict') -> Dict[str, Any]:
|
|
77
|
+
new_dict = {}
|
|
78
|
+
for key, value in d.items():
|
|
79
|
+
if type(value) in [cls, dict]:
|
|
80
|
+
new_dict[key] = cls.normal_dict(value)
|
|
81
|
+
else:
|
|
82
|
+
new_dict[key] = value
|
|
83
|
+
return new_dict
|
|
84
|
+
|
|
85
|
+
def _raise_internal_key_error(self, name: str) -> None:
|
|
86
|
+
if name.lower() in self.attribute_dict_variable:
|
|
87
|
+
raise KeyError(name)
|
|
88
|
+
|
|
89
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
|
90
|
+
if name.startswith('__') or (name in self.__dict__):
|
|
91
|
+
super(AttributeDict, self).__setattr__(name, value)
|
|
92
|
+
else:
|
|
93
|
+
self.__setitem__(name, value)
|
|
94
|
+
|
|
95
|
+
# def __getattribute__(self, name: str) -> Any:
|
|
96
|
+
# if name in super(AttributeDict, self).__getattribute__('attribute_dict_variable'):
|
|
97
|
+
# raise KeyError(f'{name} can not appears on the args_class.{self.__class__}')
|
|
98
|
+
# return super(AttributeDict, self).__getattribute__(name)
|
|
99
|
+
|
|
100
|
+
def __getattr__(self, name: str) -> Any:
|
|
101
|
+
if not self.key_in_dict(name):
|
|
102
|
+
self[name] = self.__class__()
|
|
103
|
+
return self.__getitem__(name)
|
|
104
|
+
|
|
105
|
+
def __setitem__(self, name: str, value: Any) -> Any:
|
|
106
|
+
self._raise_internal_key_error(name)
|
|
107
|
+
key_strip = name.strip()
|
|
108
|
+
key_lower = key_strip.lower()
|
|
109
|
+
if type(value) is dict:
|
|
110
|
+
new_value = self.dict_to_attributedict(value)
|
|
111
|
+
else:
|
|
112
|
+
new_value = copy(value)
|
|
113
|
+
if key_lower in self.lower_key_set:
|
|
114
|
+
true_key = self.lower_key_to_key[key_lower]
|
|
115
|
+
self.data[true_key] = new_value
|
|
116
|
+
else:
|
|
117
|
+
self.lower_key_set.add(key_lower)
|
|
118
|
+
self.lower_key_to_key[key_lower] = key_strip
|
|
119
|
+
self.data[key_strip] = new_value
|
|
120
|
+
|
|
121
|
+
def __getitem__(self, name: str) -> Any:
|
|
122
|
+
self._raise_internal_key_error(name)
|
|
123
|
+
if name.startswith('__') or (name in self.__dict__):
|
|
124
|
+
return self.__dict__[name]
|
|
125
|
+
lower_key = name.lower().strip()
|
|
126
|
+
if lower_key in self.lower_key_set:
|
|
127
|
+
return self.data[self.lower_key_to_key[lower_key]]
|
|
128
|
+
raise KeyError(name)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
class ArgsBase():
|
|
132
|
+
"""As a argument parsing base class to be extended.
|
|
133
|
+
|
|
134
|
+
basic usage:
|
|
135
|
+
1. extend this class in your class argument class
|
|
136
|
+
2. use add_default_dict_args or add_dict_args or add_keyword_value_args to add default key-value pair
|
|
137
|
+
3. use parse_input_file or parse_input_content to parse argument content
|
|
138
|
+
4. use self.args_dict to get a argument dict OR self.args_string_list(excluse) to get a list of argument string
|
|
139
|
+
|
|
140
|
+
Other feature:
|
|
141
|
+
1. set_ignore_keyword_list: to exclusive some keyword
|
|
142
|
+
2. exists_key: to judge whether key exists (for safely check) (now only support first layer check)
|
|
143
|
+
3. set_keyword_alias(standard_key, [alias_key1, alias_key2, ...])
|
|
144
|
+
4. can use add_dict_args to add a dict to the ArgsBase
|
|
145
|
+
|
|
146
|
+
Attention:
|
|
147
|
+
1. only when set dict_args and read file content can set new argument
|
|
148
|
+
2. user can use args.xxx = yyy refresh the value, but only when the key exists, the dict will refresh,
|
|
149
|
+
OR it will only add a new member var on args, so please combine it with `exists_key` to check it.
|
|
150
|
+
"""
|
|
151
|
+
ignore_list: List[str] = []
|
|
152
|
+
keyword_alias_dict: Dict[str, List[str]] = {}
|
|
153
|
+
writable: bool = True
|
|
154
|
+
data: AttributeDict
|
|
155
|
+
def __init__(self) -> None:
|
|
156
|
+
self.__dict__['data'] = AttributeDict()
|
|
157
|
+
self.__dict__['writable'] = False
|
|
158
|
+
|
|
159
|
+
def add_default_dict_args(self, keyword_list: List[str], type_or_Callable_or_value: Union[type, Callable[..., Any], Any]):
|
|
160
|
+
self.writable = True
|
|
161
|
+
if type(type_or_Callable_or_value) in [type, Callable]:
|
|
162
|
+
dd: DefaultDict[str, Any] = defaultdict(type_or_Callable_or_value)
|
|
163
|
+
for key in keyword_list:
|
|
164
|
+
self.data[key] = dd[key]
|
|
165
|
+
else:
|
|
166
|
+
for key in keyword_list:
|
|
167
|
+
self.data[key] = copy(type_or_Callable_or_value)
|
|
168
|
+
self.writable = False
|
|
169
|
+
|
|
170
|
+
# @singledispatch
|
|
171
|
+
def add_dict_args(self, dict: Dict[str, Any]):
|
|
172
|
+
AttributeDict.merge_dict(self.data, dict)
|
|
173
|
+
|
|
174
|
+
def add_keyword_value_args(self, keyword_list: List[str], value_list: List[Any]):
|
|
175
|
+
if len(keyword_list) != len(value_list):
|
|
176
|
+
self._raise_error(f'Internal Error: ArgsBase.add_keyword_value_args: the length is not equal in keyword_list and value_list')
|
|
177
|
+
d = { k: v for k, v in zip(keyword_list, value_list)}
|
|
178
|
+
self.add_dict_args(d)
|
|
179
|
+
|
|
180
|
+
@staticmethod
|
|
181
|
+
def _args_extractor(string: str) -> List[str]:
|
|
182
|
+
pair_dict = {'(': ')', '[': ']', '{': '}', '<': '>', "'": "'", '"': '"'}
|
|
183
|
+
pair_level = 0
|
|
184
|
+
pair_right: List[str] = []
|
|
185
|
+
tmp = ''
|
|
186
|
+
prev = ''
|
|
187
|
+
out_string_list: List[str] = []
|
|
188
|
+
for chr in string:
|
|
189
|
+
pair_right_last = pair_right[-1] if pair_right else ''
|
|
190
|
+
if chr in pair_dict.keys() and chr != pair_right_last:
|
|
191
|
+
pair_level += 1
|
|
192
|
+
pair_right.append(pair_dict[chr])
|
|
193
|
+
elif chr == pair_right_last:
|
|
194
|
+
pair_level -= 1
|
|
195
|
+
pair_right.pop()
|
|
196
|
+
elif chr == ' ' and pair_level == 0 and prev.strip(): # end
|
|
197
|
+
out_string_list.append(tmp)
|
|
198
|
+
tmp = ''
|
|
199
|
+
prev = chr
|
|
200
|
+
continue
|
|
201
|
+
if '"' in pair_right or "'" in pair_right:
|
|
202
|
+
tmp += chr
|
|
203
|
+
else:
|
|
204
|
+
tmp += chr.strip()
|
|
205
|
+
prev = chr
|
|
206
|
+
if pair_level:
|
|
207
|
+
stopper.stopMLatom(f'pair character unmatched args: "{tmp}"')
|
|
208
|
+
else:
|
|
209
|
+
if tmp: out_string_list.append(tmp)
|
|
210
|
+
return out_string_list
|
|
211
|
+
|
|
212
|
+
def parse_input_file(self, file: str):
|
|
213
|
+
try:
|
|
214
|
+
with open(file) as f:
|
|
215
|
+
content = f.read().splitlines()
|
|
216
|
+
except:
|
|
217
|
+
self._raise_error(f'can not open file {file}! exit!'); exit()
|
|
218
|
+
self.parse_input_content(content)
|
|
219
|
+
|
|
220
|
+
def parse_input_content(self, content: Union[List[str], str]):
|
|
221
|
+
help = False
|
|
222
|
+
if type(content) is str:
|
|
223
|
+
content = content.splitlines()
|
|
224
|
+
for c in self._clean_input_content(content):
|
|
225
|
+
splitted = c.split('=')
|
|
226
|
+
if len(splitted) == 1:
|
|
227
|
+
key = splitted[0]
|
|
228
|
+
if key.lower() in ['help', '-help', '-h', '--help']:
|
|
229
|
+
help = True
|
|
230
|
+
elif key.lower() in self.ignore_list:
|
|
231
|
+
pass
|
|
232
|
+
else:
|
|
233
|
+
restored_key = self._restore_alias_key(key)
|
|
234
|
+
self.data[restored_key] = True
|
|
235
|
+
elif len(splitted) == 2:
|
|
236
|
+
key, value = tuple(map(lambda x: x.strip(), splitted))
|
|
237
|
+
key, value = self._multi_level_dict(key, value) # has changed the type of value
|
|
238
|
+
key = self._restore_alias_key(key)
|
|
239
|
+
if type(value) in [dict, AttributeDict]:
|
|
240
|
+
AttributeDict.merge_dict(self.data, {key: value})
|
|
241
|
+
continue
|
|
242
|
+
else:
|
|
243
|
+
self.data[key] = value
|
|
244
|
+
else:
|
|
245
|
+
self._raise_error(f'error happends at your input file, error content:\n {c}')
|
|
246
|
+
if help:
|
|
247
|
+
self._print_doc()
|
|
248
|
+
|
|
249
|
+
@classmethod
|
|
250
|
+
def _multi_level_dict(cls, key: str, value: Any) -> Tuple[str, Union[AttributeDict, Dict[str, Union[str, Dict[str, Any]]]]]:
|
|
251
|
+
split_key = key.split('.')
|
|
252
|
+
real_key = split_key[0]
|
|
253
|
+
inner_value = cls._convert_to_value_with_type(copy(value))
|
|
254
|
+
for sub_key in split_key[1:][::-1]:
|
|
255
|
+
outter_dict = AttributeDict()
|
|
256
|
+
outter_dict[sub_key] = inner_value
|
|
257
|
+
inner_value = outter_dict
|
|
258
|
+
return real_key, inner_value
|
|
259
|
+
|
|
260
|
+
def _print_doc(self):
|
|
261
|
+
try: Doc.printDoc(self.args_dict)
|
|
262
|
+
except: self._warning_print('Doc not imported')
|
|
263
|
+
stopper.stopMLatom('')
|
|
264
|
+
|
|
265
|
+
@classmethod
|
|
266
|
+
def _clean_input_content(cls, content: List[str]) -> List[str]:
|
|
267
|
+
to_return: List[str] = []
|
|
268
|
+
for c in content:
|
|
269
|
+
usable = c.split('#')[0].strip()
|
|
270
|
+
while usable.find(' =') != -1:
|
|
271
|
+
usable = usable.replace(' =', '=')
|
|
272
|
+
while usable.find('= ') != -1:
|
|
273
|
+
usable = usable.replace('= ', '=')
|
|
274
|
+
to_return.extend(cls._args_extractor(usable))
|
|
275
|
+
return to_return
|
|
276
|
+
|
|
277
|
+
@property
|
|
278
|
+
def args_dict(self) -> Dict[str, Any]:
|
|
279
|
+
return AttributeDict.normal_dict(self.data)
|
|
280
|
+
|
|
281
|
+
def args_string_list(self, exclusive: List[Any]=[]) -> List[str]:
|
|
282
|
+
l = []
|
|
283
|
+
for key, value in self.args_dict.items():
|
|
284
|
+
if exclusive:
|
|
285
|
+
if value in exclusive:
|
|
286
|
+
continue
|
|
287
|
+
if value is True:
|
|
288
|
+
l.append(key)
|
|
289
|
+
elif value is False:
|
|
290
|
+
continue
|
|
291
|
+
else:
|
|
292
|
+
if type(value) is dict:
|
|
293
|
+
l.extend(self._dict_dot_expression(value, key))
|
|
294
|
+
else:
|
|
295
|
+
l.append(f'{key}={value}')
|
|
296
|
+
# l.append(f'{key}={value}')
|
|
297
|
+
return l
|
|
298
|
+
|
|
299
|
+
def _dict_dot_expression(self, d: Dict[str, Union[Dict[str, Any], Any]], key_pre_str: str='') -> List[str]:
|
|
300
|
+
str_list = []
|
|
301
|
+
for key, value in d.items():
|
|
302
|
+
if type(value) is dict:
|
|
303
|
+
str_list.extend(self._dict_dot_expression(value, f'{key_pre_str}.{key}'))
|
|
304
|
+
else:
|
|
305
|
+
str_list.append(f'{key_pre_str}.{key}={value}')
|
|
306
|
+
return str_list
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def exists_key(self, name: str) -> bool:
|
|
310
|
+
return self.exists_key(name)
|
|
311
|
+
|
|
312
|
+
def set_ignore_keyword_list(self, kw_or_list: Union[str, List[str]]):
|
|
313
|
+
if type(kw_or_list) in [list, tuple]:
|
|
314
|
+
self.ignore_list.extend(kw_or_list)
|
|
315
|
+
elif type(kw_or_list) is str:
|
|
316
|
+
self.ignore_list.append(kw_or_list)
|
|
317
|
+
else:
|
|
318
|
+
self._raise_error(f'Internal error: "set_ignore_keyword_list" can not be {kw_or_list}')
|
|
319
|
+
|
|
320
|
+
def __getattr__(self, name: str) -> Any:
|
|
321
|
+
restored_name = self._restore_alias_key(name)
|
|
322
|
+
return self.data[restored_name]
|
|
323
|
+
|
|
324
|
+
def __setattr__(self, name: str, value: Any) -> None:
|
|
325
|
+
self.__setitem__(name, value)
|
|
326
|
+
# restored_name = self._restore_alias_key(name)
|
|
327
|
+
# if self.data.key_in_dict(restored_name):
|
|
328
|
+
# self.data[restored_name] = value
|
|
329
|
+
# else:
|
|
330
|
+
# self.__dict__[name] = value
|
|
331
|
+
|
|
332
|
+
def set_keyword_alias(self, standard: str, alias: Union[str, Sequence[str]]) -> None:
|
|
333
|
+
if type(alias) is str:
|
|
334
|
+
self.keyword_alias_dict[standard] = [alias.lower()]
|
|
335
|
+
else:
|
|
336
|
+
self.keyword_alias_dict[standard] = list(map(lambda x: x.lower(), alias))
|
|
337
|
+
|
|
338
|
+
def _restore_alias_key(self, key: str) -> str:
|
|
339
|
+
for std_key, alias_list in self.keyword_alias_dict.items():
|
|
340
|
+
if key.lower().strip() in alias_list:
|
|
341
|
+
return std_key
|
|
342
|
+
return key
|
|
343
|
+
|
|
344
|
+
def __getitem__(self, name: str) -> Any:
|
|
345
|
+
restored_name = self._restore_alias_key(name)
|
|
346
|
+
return self.data[restored_name]
|
|
347
|
+
|
|
348
|
+
def __setitem__(self, name: str, value: Any) -> None:
|
|
349
|
+
restored_name = self._restore_alias_key(name)
|
|
350
|
+
if self.data.key_in_dict(restored_name):
|
|
351
|
+
self.data[restored_name] = value
|
|
352
|
+
else:
|
|
353
|
+
self.__dict__[name] = value
|
|
354
|
+
|
|
355
|
+
@staticmethod
|
|
356
|
+
def _raise_error(content: str) -> None:
|
|
357
|
+
print('WARNING ' * 10)
|
|
358
|
+
print(' <!> %s <!>' % content)
|
|
359
|
+
print('WARNING ' * 10)
|
|
360
|
+
exit()
|
|
361
|
+
|
|
362
|
+
@staticmethod
|
|
363
|
+
def _warning_print(warning: str) -> None:
|
|
364
|
+
print('-' * 80)
|
|
365
|
+
print(' warning: %s :warning' % warning)
|
|
366
|
+
print('-' * 80)
|
|
367
|
+
|
|
368
|
+
@staticmethod
|
|
369
|
+
def _convert_to_value_with_type(value: Any) -> Any:
|
|
370
|
+
if type(value) in [dict, AttributeDict]:
|
|
371
|
+
return value
|
|
372
|
+
if value.strip().lower() == 'true':
|
|
373
|
+
return True
|
|
374
|
+
elif value.strip().lower() == 'false':
|
|
375
|
+
return False
|
|
376
|
+
else:
|
|
377
|
+
try:
|
|
378
|
+
tmp = int(value)
|
|
379
|
+
except:
|
|
380
|
+
try:
|
|
381
|
+
tmp = float(value)
|
|
382
|
+
except:
|
|
383
|
+
return value
|
|
384
|
+
else:
|
|
385
|
+
return tmp
|
|
386
|
+
else:
|
|
387
|
+
return tmp
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
if __name__ == '__main__':
|
|
391
|
+
try:
|
|
392
|
+
args = ArgsBase()
|
|
393
|
+
args.parse_input_file('inp')
|
|
394
|
+
except: pass
|
|
395
|
+
print( 'warning: you are directly running the module: args_class, '\
|
|
396
|
+
'which should be extended by a class, not run it.')
|
MLatom/cs.so
ADDED
|
Binary file
|