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
|
@@ -0,0 +1,415 @@
|
|
|
1
|
+
#!/usr/bin/python3
|
|
2
|
+
'''
|
|
3
|
+
!---------------------------------------------------------------------------!
|
|
4
|
+
! Interface_GAP: Interface between GAP and MLatom !
|
|
5
|
+
! Implementations by: Fuchun Ge !
|
|
6
|
+
!---------------------------------------------------------------------------!
|
|
7
|
+
'''
|
|
8
|
+
import numpy as np
|
|
9
|
+
import os, sys, subprocess, time, shutil, re, math, random
|
|
10
|
+
import stopper
|
|
11
|
+
from args_class import ArgsBase
|
|
12
|
+
|
|
13
|
+
filedir = os.path.dirname(__file__)
|
|
14
|
+
|
|
15
|
+
class Args(ArgsBase):
|
|
16
|
+
def __init__(self):
|
|
17
|
+
super().__init__()
|
|
18
|
+
self.add_default_dict_args([
|
|
19
|
+
'learningCurve'
|
|
20
|
+
],
|
|
21
|
+
bool
|
|
22
|
+
)
|
|
23
|
+
self.add_default_dict_args([
|
|
24
|
+
'mlmodeltype'
|
|
25
|
+
],
|
|
26
|
+
'gap-soap'
|
|
27
|
+
)
|
|
28
|
+
self.add_default_dict_args([
|
|
29
|
+
'xyzfile', 'yfile', 'ygradxyzfile','itrainin','itestin','isubtrainin','ivalidatein','mlmodelin','setname'
|
|
30
|
+
],
|
|
31
|
+
""
|
|
32
|
+
)
|
|
33
|
+
self.add_dict_args({
|
|
34
|
+
'mlmodelout': "GAPmodel.xml",
|
|
35
|
+
'sampling': "random",
|
|
36
|
+
'yestfile': "enest.dat",
|
|
37
|
+
'ygradxyzestfile': "gradest.dat"
|
|
38
|
+
})
|
|
39
|
+
self.parse_input_content('gapfit.gap.type=soap')
|
|
40
|
+
|
|
41
|
+
def parse(self, argsraw):
|
|
42
|
+
self.parse_input_content(argsraw)
|
|
43
|
+
self.argProcess()
|
|
44
|
+
|
|
45
|
+
def argProcess(self):
|
|
46
|
+
GAPCls.gapdict.update(self.gapfit.gap)
|
|
47
|
+
gap = '{'+' '.join([str(k)+'='+str(v) for k,v in GAPCls.gapdict.items()])[5:]+'}'
|
|
48
|
+
GAPCls.gapfitdict.update(self.gapfit)
|
|
49
|
+
GAPCls.gapfitdict.update({
|
|
50
|
+
'gp_file': self.mlmodelout,
|
|
51
|
+
'gap': gap,
|
|
52
|
+
})
|
|
53
|
+
with open(self.xyzfile,'r') as f:
|
|
54
|
+
GAPCls.natom = int(f.readline())
|
|
55
|
+
exec('f.readline()')
|
|
56
|
+
GAPCls.atype = [f.readline().split()[0] for i in range(GAPCls.natom)]
|
|
57
|
+
|
|
58
|
+
if not self.mlmodelin:
|
|
59
|
+
self.mlmodelin = self.mlmodelout
|
|
60
|
+
if 'default_sigma_e' in GAPCls.gapfitdict.keys():
|
|
61
|
+
GAPCls.gapfitdict['default_sigma']=GAPCls.gapfitdict['default_sigma'].replace(
|
|
62
|
+
GAPCls.gapfitdict['default_sigma'][1:-1].split(',')[0],
|
|
63
|
+
GAPCls.gapfitdict['default_sigma_e']
|
|
64
|
+
)
|
|
65
|
+
GAPCls.gapfitdict.pop('default_sigma_e')
|
|
66
|
+
if 'default_sigma_f' in GAPCls.gapfitdict.keys():
|
|
67
|
+
GAPCls.gapfitdict['default_sigma']=GAPCls.gapfitdict['default_sigma'].replace(
|
|
68
|
+
GAPCls.gapfitdict['default_sigma'][1:-1].split(',')[1],
|
|
69
|
+
GAPCls.gapfitdict['default_sigma_f']
|
|
70
|
+
)
|
|
71
|
+
GAPCls.gapfitdict.pop('default_sigma_f')
|
|
72
|
+
GAPCls.gapfitdict['default_sigma'] = " ".join(GAPCls.gapfitdict['default_sigma'].replace(',',', ').split())
|
|
73
|
+
GAPCls.gapfitdict['gp_file']=self.mlmodelout
|
|
74
|
+
if self.yfile: GAPCls.gapfitdict['energy_parameter_name']='energy'
|
|
75
|
+
if self.ygradxyzfile: GAPCls.gapfitdict['force_parameter_name']='forces'
|
|
76
|
+
# if self.setname: GAPCls.gapfitdict['at_file']='GAP.exyz_'+self.setname
|
|
77
|
+
GAPCls.gapfit = [GAPbin]
|
|
78
|
+
for k, v in GAPCls.gapfitdict.items():
|
|
79
|
+
GAPCls.gapfit.append(k+'='+v)
|
|
80
|
+
|
|
81
|
+
class GAPCls(object):
|
|
82
|
+
dataConverted = False
|
|
83
|
+
gapdict = {
|
|
84
|
+
'type': 'soap',
|
|
85
|
+
'l_max': '6',
|
|
86
|
+
'n_max': '6',
|
|
87
|
+
'atom_sigma': '0.5',
|
|
88
|
+
'zeta': '4',
|
|
89
|
+
'cutoff': '6',
|
|
90
|
+
'cutoff_transition_width': '0.5',
|
|
91
|
+
'n_sparse': '1000000',
|
|
92
|
+
'delta': '1',
|
|
93
|
+
'covariance_type': 'dot_product',
|
|
94
|
+
'sparse_method': 'cur_points',
|
|
95
|
+
'add_species': 'T'
|
|
96
|
+
}
|
|
97
|
+
# gap = '{'+' '.join([k+'='+v for k,v in args.gapdic.items()])[5:]+'}'
|
|
98
|
+
gapfitdict = {
|
|
99
|
+
'at_file':'GAP.exyz_train',
|
|
100
|
+
'default_sigma':'{0.0005,0.001,0.1,0.1}',
|
|
101
|
+
'gp_file': '',
|
|
102
|
+
'gap': '',
|
|
103
|
+
'e0_method':'average',
|
|
104
|
+
'sparse_separate_file': 'F'
|
|
105
|
+
}
|
|
106
|
+
gapfit = []
|
|
107
|
+
natom = 0
|
|
108
|
+
atype = ''
|
|
109
|
+
|
|
110
|
+
@classmethod
|
|
111
|
+
def load(cls):
|
|
112
|
+
loaded=False
|
|
113
|
+
if not loaded:
|
|
114
|
+
|
|
115
|
+
try:
|
|
116
|
+
GAPbin = os.environ['gap_fit']
|
|
117
|
+
except:
|
|
118
|
+
print('please set $gap_fit')
|
|
119
|
+
try:
|
|
120
|
+
QUIPbin = os.environ['quip']
|
|
121
|
+
except:
|
|
122
|
+
print('please set $quip')
|
|
123
|
+
globals()['QUIPbin'] = QUIPbin
|
|
124
|
+
globals()['GAPbin'] = GAPbin
|
|
125
|
+
loaded=True
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
def __init__(self, args = sys.argv[1:]):
|
|
130
|
+
print(' ___________________________________________________________\n\n%s' % __doc__)
|
|
131
|
+
|
|
132
|
+
@classmethod
|
|
133
|
+
def convertdata(cls, GAPargs, subdatasets):
|
|
134
|
+
cls.load()
|
|
135
|
+
def convert(fileout, setname, yorgrad=False):
|
|
136
|
+
# convert data to .exyz format
|
|
137
|
+
prefix = ''
|
|
138
|
+
if args.learningcurve: prefix = '../'
|
|
139
|
+
if setname:
|
|
140
|
+
coordfile = prefix+'xyz.dat_'+setname
|
|
141
|
+
yfile = prefix+'y.dat_'+setname
|
|
142
|
+
gradfile = prefix+'grad.dat_'+setname
|
|
143
|
+
else:
|
|
144
|
+
coordfile = args.xyzfile
|
|
145
|
+
if args.yfile and yorgrad: yfile = args.yfile
|
|
146
|
+
if args.ygradxyzfile and yorgrad: gradfile = args.ygradxyzfile
|
|
147
|
+
|
|
148
|
+
with open(fileout, 'w') as fo, open(coordfile ,'r') as fxyz:
|
|
149
|
+
if args.yfile and yorgrad: fy = open(yfile,'r')
|
|
150
|
+
if args.ygradxyzfile and yorgrad: fgrad = open(gradfile,'r')
|
|
151
|
+
for line in fxyz:
|
|
152
|
+
natom = int(line)
|
|
153
|
+
fo.write(line)
|
|
154
|
+
if args.ygradxyzfile and yorgrad: fgrad.readline()
|
|
155
|
+
|
|
156
|
+
if args.yfile and yorgrad: fo.write('energy=%s '% fy.readline()[:-1])
|
|
157
|
+
fo.write('pbc="T T T" Lattice="10.0 0.0 0.0 0.0 10.0 0.0 0.0 0.0 10.0" Properties=species:S:1:pos:R:3')
|
|
158
|
+
if args.ygradxyzfile and yorgrad: fo.write(':forces:R:3')
|
|
159
|
+
fo.write('\n')
|
|
160
|
+
fxyz.readline()
|
|
161
|
+
if args.ygradxyzfile and yorgrad: fgrad.readline()
|
|
162
|
+
|
|
163
|
+
for i in range(natom):
|
|
164
|
+
fo.write(fxyz.readline()[:-1])
|
|
165
|
+
if args.ygradxyzfile and yorgrad:
|
|
166
|
+
fo.write('%24.15f%24.15f%24.15f' % tuple(-1*float(i) for i in fgrad.readline().split()[-3:]))
|
|
167
|
+
fo.write('\n')
|
|
168
|
+
if args.yfile and yorgrad: fy.close()
|
|
169
|
+
if args.ygradxyzfile and yorgrad: fgrad.close()
|
|
170
|
+
args = Args()
|
|
171
|
+
args.parse(GAPargs)
|
|
172
|
+
print('\n Converting data...\n\n')
|
|
173
|
+
if subdatasets:
|
|
174
|
+
if 'Subtrain' in subdatasets:
|
|
175
|
+
for i in subdatasets:
|
|
176
|
+
if i == 'Subtrain' or 'Train': convert('GAP.exyz_'+i.lower(), i.lower(),True)
|
|
177
|
+
else: convert('GAP.exyz_'+i.lower(), i.lower())
|
|
178
|
+
else:
|
|
179
|
+
for i in subdatasets:
|
|
180
|
+
if i == 'Train': convert('GAP.exyz_'+i.lower(), i.lower(),True)
|
|
181
|
+
else: convert('GAP.exyz_'+i.lower(), i.lower())
|
|
182
|
+
else: convert('GAP.exyz', '')
|
|
183
|
+
|
|
184
|
+
@classmethod
|
|
185
|
+
def createMLmodel(cls, GAPargs, subdatasets):
|
|
186
|
+
cls.load()
|
|
187
|
+
|
|
188
|
+
args = Args()
|
|
189
|
+
args.parse(GAPargs)
|
|
190
|
+
|
|
191
|
+
if not cls.dataConverted or args.learningcurve:
|
|
192
|
+
cls.convertdata(GAPargs, subdatasets)
|
|
193
|
+
cls.dataConverted = True
|
|
194
|
+
|
|
195
|
+
FNULL = open(os.devnull, 'w')
|
|
196
|
+
|
|
197
|
+
os.system('rm '+args.mlmodelout+'* > /dev/null 2>&1 ')
|
|
198
|
+
# call gap_fitr
|
|
199
|
+
starttime = time.time()
|
|
200
|
+
print('> '+' '.join(cls.gapfit))
|
|
201
|
+
sys.stdout.flush()
|
|
202
|
+
|
|
203
|
+
subprocess.call(cls.gapfit, stdout=FNULL, stderr=FNULL)
|
|
204
|
+
# subprocess.call(args.gapfit)
|
|
205
|
+
FNULL.close()
|
|
206
|
+
endtime = time.time()
|
|
207
|
+
wallclock = endtime - starttime
|
|
208
|
+
|
|
209
|
+
return wallclock
|
|
210
|
+
|
|
211
|
+
@classmethod
|
|
212
|
+
def useMLmodel(cls, GAPargs, subdatasets):
|
|
213
|
+
cls.load()
|
|
214
|
+
|
|
215
|
+
args = Args()
|
|
216
|
+
|
|
217
|
+
if not cls.dataConverted:
|
|
218
|
+
cls.convertdata(GAPargs, subdatasets)
|
|
219
|
+
cls.dataConverted = True
|
|
220
|
+
|
|
221
|
+
args.parse(GAPargs)
|
|
222
|
+
if args.setname: args.setname='_'+args.setname
|
|
223
|
+
|
|
224
|
+
starttime = time.time()
|
|
225
|
+
|
|
226
|
+
p1 = subprocess.Popen([
|
|
227
|
+
QUIPbin,
|
|
228
|
+
'E=T',
|
|
229
|
+
'F=T',
|
|
230
|
+
'atoms_filename=GAP.exyz'+args.setname,
|
|
231
|
+
'param_filename='+args.mlmodelin,
|
|
232
|
+
], stdout=subprocess.PIPE)
|
|
233
|
+
p2 = subprocess.Popen(['grep','AT'], stdin=p1.stdout, stdout=subprocess.PIPE)
|
|
234
|
+
(stdout, stderr) = p2.communicate()
|
|
235
|
+
p1.stdout.close()
|
|
236
|
+
with open('GAPest.exyz'+args.setname,'w') as f:
|
|
237
|
+
f.write(stdout.decode('ascii'))
|
|
238
|
+
|
|
239
|
+
endtime = time.time()
|
|
240
|
+
wallclock = endtime - starttime
|
|
241
|
+
|
|
242
|
+
# convert results back to MLatom format
|
|
243
|
+
with open('GAPest.exyz'+args.setname,'r') as f, open(args.yestfile,'w') as fy, open(args.ygradxyzestfile,'w') as fgrad:
|
|
244
|
+
for i, line in enumerate(f):
|
|
245
|
+
if i%(cls.natom+2) == 0:
|
|
246
|
+
fgrad.write(line[3:])
|
|
247
|
+
elif i%(cls.natom+2) ==1:
|
|
248
|
+
fgrad.write('\n')
|
|
249
|
+
fy.write(line.split()[1].split('=')[1]+'\n')
|
|
250
|
+
else:
|
|
251
|
+
fgrad.write('%20s%20s%20s\n' % tuple([-1*float(i) for i in line.split()[-3:]]))
|
|
252
|
+
sys.stdout.flush()
|
|
253
|
+
os.system('rm GAP.exyz'+args.setname+'.idx > /dev/null 2>&1 ')
|
|
254
|
+
args.setname='train'
|
|
255
|
+
return wallclock
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
# class args(object):
|
|
259
|
+
# # MLatom args
|
|
260
|
+
# learningcurve = False
|
|
261
|
+
# xyzfile = ""
|
|
262
|
+
# yfile = ""
|
|
263
|
+
# ygradxyzfile = ""
|
|
264
|
+
# virialfile = ""
|
|
265
|
+
# ntrain = 0
|
|
266
|
+
# ntest = 0
|
|
267
|
+
# nsubtrain = 0
|
|
268
|
+
# nvalidate = 0
|
|
269
|
+
# sampling = "random"
|
|
270
|
+
# itrainin = ""
|
|
271
|
+
# itestin = ""
|
|
272
|
+
# isubtrainin = ""
|
|
273
|
+
# ivalidatein = ""
|
|
274
|
+
# mlmodelout = "GAPmodel.xml"
|
|
275
|
+
# mlmodelin = ""
|
|
276
|
+
# yestfile = "enest.dat"
|
|
277
|
+
# ygradxyzestfile = "gradest.dat"
|
|
278
|
+
|
|
279
|
+
# # args for this interface
|
|
280
|
+
# setname = ''
|
|
281
|
+
# natom = 0
|
|
282
|
+
# atype = []
|
|
283
|
+
# gapdic = {
|
|
284
|
+
# 'type': 'soap',
|
|
285
|
+
# 'l_max': '6',
|
|
286
|
+
# 'n_max': '6',
|
|
287
|
+
# 'atom_sigma': '0.5',
|
|
288
|
+
# 'zeta': '4',
|
|
289
|
+
# 'cutoff': '6',
|
|
290
|
+
# 'cutoff_transition_width': '0.5',
|
|
291
|
+
# 'n_sparse': '1000000',
|
|
292
|
+
# 'delta': '1',
|
|
293
|
+
# 'covariance_type': 'dot_product',
|
|
294
|
+
# 'sparse_method': 'cur_points',
|
|
295
|
+
# 'add_species': 'T'
|
|
296
|
+
# }
|
|
297
|
+
# gap = '{'+' '.join([k+'='+v for k,v in gapdic.items()])[5:]+'}'
|
|
298
|
+
# gapfitdic = {
|
|
299
|
+
# 'at_file':'GAP.exyz_train',
|
|
300
|
+
# 'default_sigma':'{0.0005,0.001,0.1,0.1}',
|
|
301
|
+
# 'gp_file': mlmodelout,
|
|
302
|
+
# 'gap': gap,
|
|
303
|
+
# 'e0_method':'average',
|
|
304
|
+
# 'sparse_separate_file': 'F'
|
|
305
|
+
# }
|
|
306
|
+
# gapfit = []
|
|
307
|
+
|
|
308
|
+
# @classmethod
|
|
309
|
+
# def parse(cls,argsraw):
|
|
310
|
+
# if len(argsraw) == 0:
|
|
311
|
+
# printHelp()
|
|
312
|
+
# stopper.stopMLatom('At least one option should be provided')
|
|
313
|
+
# for arg in argsraw:
|
|
314
|
+
# if (arg.lower() == 'help'
|
|
315
|
+
# or arg.lower() == '-help'
|
|
316
|
+
# or arg.lower() == '-h'
|
|
317
|
+
# or arg.lower() == '--help'):
|
|
318
|
+
# printHelp()
|
|
319
|
+
# stopper.stopMLatom('')
|
|
320
|
+
# elif arg.lower().split('=')[0] == 'gapfit':
|
|
321
|
+
# exec(arg)
|
|
322
|
+
# print(gapfit)
|
|
323
|
+
# test=gapfit['gap']
|
|
324
|
+
# elif arg.lower().split('.')[0] in ['gap-soap', 'gap', 'gap_fit', 'gapfit']:
|
|
325
|
+
# if arg.lower().split('.')[1]=="gap":
|
|
326
|
+
# exec('cls.gapdic[arg.split(".")[2].split("=")[0]]=arg.split("=",1)[1]')
|
|
327
|
+
# cls.gap = '{'+' '.join([k+'='+v for k,v in cls.gapdic.items()])[5:]+'}'
|
|
328
|
+
# GAPCls.gapfitdict['gap']=cls.gap
|
|
329
|
+
# else:
|
|
330
|
+
# exec('GAPCls.gapfitdict[arg.split(".")[1].split("=")[0]]=arg.split("=",1)[1]')
|
|
331
|
+
# elif len(arg.lower().split('=')) == 1: # parse boolean args
|
|
332
|
+
# try:
|
|
333
|
+
# exec('cls.'+arg.lower())
|
|
334
|
+
# exec('cls.'+arg.lower()+'=True')
|
|
335
|
+
# except: pass
|
|
336
|
+
# else: # parse other args
|
|
337
|
+
# try:
|
|
338
|
+
# exec('cls.'+arg.split('=')[0].lower())
|
|
339
|
+
# if type(eval('cls.'+arg.split('=')[0].lower())) == str :
|
|
340
|
+
# exec('cls.'+arg.split('=')[0].lower()+'='+"arg.split('=')[1]")
|
|
341
|
+
# else:
|
|
342
|
+
# exec('cls.'+arg.split('=')[0].lower()+'='+arg.split('=')[1])
|
|
343
|
+
# except:
|
|
344
|
+
# pass
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
# # calc. & fix something args that useful and you don't want users to change...
|
|
348
|
+
# with open(cls.xyzfile,'r') as f:
|
|
349
|
+
# cls.natom = int(f.readline())
|
|
350
|
+
# exec('f.readline()')
|
|
351
|
+
# cls.atype = [f.readline().split()[0] for i in range(cls.natom)]
|
|
352
|
+
|
|
353
|
+
# # for estAccMLmodel that MLmodelIn may not be provided
|
|
354
|
+
# if not cls.mlmodelin:
|
|
355
|
+
# cls.mlmodelin = cls.mlmodelout
|
|
356
|
+
# if 'default_sigma_e' in GAPCls.gapfitdict.keys():
|
|
357
|
+
# GAPCls.gapfitdict['default_sigma']=GAPCls.gapfitdict['default_sigma'].replace(
|
|
358
|
+
# GAPCls.gapfitdict['default_sigma'][1:-1].split(',')[0],
|
|
359
|
+
# GAPCls.gapfitdict['default_sigma_e']
|
|
360
|
+
# )
|
|
361
|
+
# GAPCls.gapfitdict.pop('default_sigma_e')
|
|
362
|
+
# if 'default_sigma_f' in GAPCls.gapfitdict.keys():
|
|
363
|
+
# GAPCls.gapfitdict['default_sigma']=GAPCls.gapfitdict['default_sigma'].replace(
|
|
364
|
+
# GAPCls.gapfitdict['default_sigma'][1:-1].split(',')[1],
|
|
365
|
+
# GAPCls.gapfitdict['default_sigma_f']
|
|
366
|
+
# )
|
|
367
|
+
# GAPCls.gapfitdict.pop('default_sigma_f')
|
|
368
|
+
# GAPCls.gapfitdict['default_sigma'] = " ".join(GAPCls.gapfitdict['default_sigma'].replace(',',', ').split())
|
|
369
|
+
# GAPCls.gapfitdict['gp_file']=cls.mlmodelout
|
|
370
|
+
# if cls.yfile: GAPCls.gapfitdict['energy_parameter_name']='energy'
|
|
371
|
+
# if cls.ygradxyzfile: GAPCls.gapfitdict['force_parameter_name']='forces'
|
|
372
|
+
# if cls.setname: GAPCls.gapfitdict['at_file']='GAP.exyz_'+cls.setname
|
|
373
|
+
# cls.gapfit = [GAPbin]
|
|
374
|
+
# for k, v in GAPCls.gapfitdict.items():
|
|
375
|
+
# cls.gapfit.append(k+'='+v)
|
|
376
|
+
|
|
377
|
+
|
|
378
|
+
def printHelp():
|
|
379
|
+
helpText = __doc__ + '''
|
|
380
|
+
To use Interface_GAP, please define $gap_fit and $quip
|
|
381
|
+
to corresponding executables
|
|
382
|
+
|
|
383
|
+
Arguments with their default values:
|
|
384
|
+
MLprog=GAP enables this interface
|
|
385
|
+
MLmodelType=GAP-SOAP requests GAP-SOAP model
|
|
386
|
+
|
|
387
|
+
gapfit.xxx=x xxx could be any option for gap_fit
|
|
388
|
+
Note that at_file and gp_file are not required
|
|
389
|
+
gapfit.gap.xxx=x xxx could be any option for gap
|
|
390
|
+
gapfit.default_sigma={0.0005,0.001,0,0}
|
|
391
|
+
sigmas for energies, forces, virals, Hessians
|
|
392
|
+
gapfit.e0_method=average method for determining e0
|
|
393
|
+
gapfit.gap.type=soap descriptor type
|
|
394
|
+
gapfit.gap.l_max=6 max number of angular basis functions
|
|
395
|
+
gapfit.gap.n_max=6 max number of radial basis functions
|
|
396
|
+
gapfit.gap.atom_sigma=0.5 Gaussian smearing of atom density hyperparameter
|
|
397
|
+
|
|
398
|
+
gapfit.gap.zeta=4 hyperparameter for kernel sensitivity
|
|
399
|
+
gapfit.gap.cutoff=6.0 cutoff radius of local environment
|
|
400
|
+
gapfit.gap.cutoff_transition_width=0.5
|
|
401
|
+
cutoff transition width
|
|
402
|
+
gapfit.gap.delta=1 hyperparameter delta for kernel scaling
|
|
403
|
+
|
|
404
|
+
Cite GAP method:
|
|
405
|
+
A. P. Bartok, M. C. Payne, R. Konor, G. Csanyi,
|
|
406
|
+
Phys. Rev. Lett. 2010, 104, 136403
|
|
407
|
+
|
|
408
|
+
Cite SOAP descriptor:
|
|
409
|
+
A. P. Bartok, R. Konor, G. Csanyi,
|
|
410
|
+
Phys. Rev. B 2013, 87, 184115
|
|
411
|
+
'''
|
|
412
|
+
print(helpText)
|
|
413
|
+
|
|
414
|
+
if __name__ == '__main__':
|
|
415
|
+
GAPCls()
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
import os
|
|
5
|
+
import sys
|
|
6
|
+
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
|
|
7
|
+
|
|
8
|
+
PhysNetdir = os.environ['PhysNet']
|
|
9
|
+
sys.path.append(PhysNetdir)
|
|
10
|
+
|
|
11
|
+
import tensorflow.compat.v1 as tf
|
|
12
|
+
tf.disable_v2_behavior()
|
|
13
|
+
import time
|
|
14
|
+
import argparse
|
|
15
|
+
import logging
|
|
16
|
+
logging.getLogger('tensorflow').disabled = True
|
|
17
|
+
|
|
18
|
+
from datetime import datetime
|
|
19
|
+
from neural_network.NeuralNetwork import *
|
|
20
|
+
from neural_network.activation_fn import *
|
|
21
|
+
from training.DataContainer import *
|
|
22
|
+
from training.DataProvider import *
|
|
23
|
+
|
|
24
|
+
def predict(PNargs):
|
|
25
|
+
tf.compat.v1.reset_default_graph()
|
|
26
|
+
#define command line arguments
|
|
27
|
+
parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
|
|
28
|
+
parser.add_argument("--restart", type=str, default=None, help="restart training from a specific folder")
|
|
29
|
+
parser.add_argument("--num_features", type=int, help="dimensionality of feature vectors")
|
|
30
|
+
parser.add_argument("--num_basis", type=int, help="number of radial basis functions")
|
|
31
|
+
parser.add_argument("--num_blocks", type=int, help="number of interaction blocks")
|
|
32
|
+
parser.add_argument("--num_residual_atomic", type=int, help="number of residual layers for atomic refinements")
|
|
33
|
+
parser.add_argument("--num_residual_interaction", type=int, help="number of residual layers for the message phase")
|
|
34
|
+
parser.add_argument("--num_residual_output", type=int, help="number of residual layers for the output blocks")
|
|
35
|
+
parser.add_argument("--cutoff", default=10.0, type=float, help="cutoff distance for short range interactions")
|
|
36
|
+
parser.add_argument("--use_electrostatic", default=1, type=int, help="use electrostatics in energy prediction (0/1)")
|
|
37
|
+
parser.add_argument("--use_dispersion", default=1, type=int, help="use dispersion in energy prediction (0/1)")
|
|
38
|
+
parser.add_argument("--grimme_s6", default=None, type=float, help="grimme s6 dispersion coefficient")
|
|
39
|
+
parser.add_argument("--grimme_s8", default=None, type=float, help="grimme s8 dispersion coefficient")
|
|
40
|
+
parser.add_argument("--grimme_a1", default=None, type=float, help="grimme a1 dispersion coefficient")
|
|
41
|
+
parser.add_argument("--grimme_a2", default=None, type=float, help="grimme a2 dispersion coefficient")
|
|
42
|
+
parser.add_argument("--num_train", type=int, help="number of training samples")
|
|
43
|
+
parser.add_argument("--num_valid", type=int, help="number of validation samples")
|
|
44
|
+
parser.add_argument("--seed", default=42, type=int, help="seed for splitting dataset into training/validation/test")
|
|
45
|
+
parser.add_argument("--max_steps", type=int, help="maximum number of training steps")
|
|
46
|
+
parser.add_argument("--learning_rate", default=0.001, type=float, help="learning rate used by the optimizer")
|
|
47
|
+
parser.add_argument("--max_norm", default=1000.0, type=float, help="max norm for gradient clipping")
|
|
48
|
+
parser.add_argument("--ema_decay", default=0.999, type=float, help="exponential moving average decay used by the trainer")
|
|
49
|
+
parser.add_argument("--keep_prob", default=1.0, type=float, help="keep probability for dropout regularization of rbf layer")
|
|
50
|
+
parser.add_argument("--l2lambda", type=float, help="lambda multiplier for l2 loss (regularization)")
|
|
51
|
+
parser.add_argument("--nhlambda", type=float, help="lambda multiplier for non-hierarchicality loss (regularization)")
|
|
52
|
+
parser.add_argument("--decay_steps", type=int, help="decay the learning rate every N steps by decay_rate")
|
|
53
|
+
parser.add_argument("--decay_rate", type=float, help="factor with which the learning rate gets multiplied by every decay_steps steps")
|
|
54
|
+
parser.add_argument("--batch_size", type=int, help="batch size used per training step")
|
|
55
|
+
parser.add_argument("--valid_batch_size", type=int, help="batch size used for going through validation_set")
|
|
56
|
+
parser.add_argument('--force_weight', default=52.91772105638412, type=float, help="this defines the force contribution to the loss function relative to the energy contribution (to take into account the different numerical range)")
|
|
57
|
+
parser.add_argument('--charge_weight', default=14.399645351950548, type=float, help="this defines the charge contribution to the loss function relative to the energy contribution (to take into account the different numerical range)")
|
|
58
|
+
parser.add_argument('--dipole_weight', default=27.211386024367243, type=float, help="this defines the dipole contribution to the loss function relative to the energy contribution (to take into account the different numerical range)")
|
|
59
|
+
parser.add_argument('--summary_interval', type=int, help="write a summary every N steps")
|
|
60
|
+
parser.add_argument('--validation_interval', type=int, help="check performance on validation set every N steps")
|
|
61
|
+
parser.add_argument('--save_interval', type=int, help="save progress every N steps")
|
|
62
|
+
parser.add_argument('--record_run_metadata', type=int, help="records metadata like memory consumption etc.")
|
|
63
|
+
|
|
64
|
+
#if no command line arguments are present, config file is parsed
|
|
65
|
+
config_file = os.path.join(PNargs.mlmodelin, 'config.txt')
|
|
66
|
+
|
|
67
|
+
if os.path.isfile(config_file):
|
|
68
|
+
args = parser.parse_args(["@"+config_file])
|
|
69
|
+
else:
|
|
70
|
+
args = parser.parse_args(["--help"])
|
|
71
|
+
if PNargs.setname: PNargs.setname='_'+PNargs.setname
|
|
72
|
+
#construct file path to directory which stores the best checkpoint files
|
|
73
|
+
best_dir = os.path.join(PNargs.mlmodelin, 'best')
|
|
74
|
+
testfile = 'PhysNet'+PNargs.setname+'.npz'
|
|
75
|
+
#load dataset
|
|
76
|
+
data = DataContainer(testfile)
|
|
77
|
+
|
|
78
|
+
data_provider = DataProvider(data, 0, 0, 0, 0, seed=args.seed)
|
|
79
|
+
|
|
80
|
+
#create neural network
|
|
81
|
+
# NASdict = np.load(os.path.join(PNargs.mlmodelin, 'NAS.npz'))
|
|
82
|
+
# tf.reset_default_graph()
|
|
83
|
+
nn = NeuralNetwork(F=args.num_features,
|
|
84
|
+
K=args.num_basis,
|
|
85
|
+
sr_cut=args.cutoff,
|
|
86
|
+
num_blocks=args.num_blocks,
|
|
87
|
+
num_residual_atomic=args.num_residual_atomic,
|
|
88
|
+
num_residual_interaction=args.num_residual_interaction,
|
|
89
|
+
num_residual_output=args.num_residual_output,
|
|
90
|
+
use_electrostatic=(args.use_electrostatic==1),
|
|
91
|
+
use_dispersion=(args.use_dispersion==1),
|
|
92
|
+
s6=args.grimme_s6,
|
|
93
|
+
s8=args.grimme_s8,
|
|
94
|
+
a1=args.grimme_a1,
|
|
95
|
+
a2=args.grimme_a2,
|
|
96
|
+
# Eshift=NASdict['Eshift'],
|
|
97
|
+
# Escale=NASdict['Escale'],
|
|
98
|
+
activation_fn=shifted_softplus,
|
|
99
|
+
seed=None,
|
|
100
|
+
scope="neural_network")
|
|
101
|
+
#create placeholders for feeding data
|
|
102
|
+
Eref = tf.placeholder(tf.float32, shape=[None, ], name="Eref")
|
|
103
|
+
Fref = tf.placeholder(tf.float32, shape=[None,3], name="Fref")
|
|
104
|
+
Z = tf.placeholder(tf.int32, shape=[None, ], name="Z")
|
|
105
|
+
Dref = tf.placeholder(tf.float32, shape=[None,3], name="Dref")
|
|
106
|
+
Qref = tf.placeholder(tf.float32, shape=[None, ], name="Qref")
|
|
107
|
+
R = tf.placeholder(tf.float32, shape=[None,3], name="R")
|
|
108
|
+
idx_i = tf.placeholder(tf.int32, shape=[None, ], name="idx_i")
|
|
109
|
+
idx_j = tf.placeholder(tf.int32, shape=[None, ], name="idx_j")
|
|
110
|
+
batch_seg = tf.placeholder(tf.int32, shape=[None, ], name="batch_seg")
|
|
111
|
+
|
|
112
|
+
#model energy/forces
|
|
113
|
+
Ea, Qa, Dij, nhloss = nn.atomic_properties(Z, R, idx_i, idx_j)
|
|
114
|
+
energy, forces = nn.energy_and_forces_from_atomic_properties(Ea, Qa, Dij, Z, R, idx_i, idx_j, Qref, batch_seg)
|
|
115
|
+
#total charge
|
|
116
|
+
Qtot = tf.segment_sum(Qa, batch_seg)
|
|
117
|
+
#dipole moment vector
|
|
118
|
+
QR = tf.stack([Qa*R[:,0], Qa*R[:,1], Qa*R[:,2]],1)
|
|
119
|
+
D = tf.segment_sum(QR, batch_seg)
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
#helper function to fill a feed dictionary
|
|
124
|
+
def fill_feed_dict(data):
|
|
125
|
+
feed_dict = {
|
|
126
|
+
Eref: data["E"],
|
|
127
|
+
Fref: data["F"],
|
|
128
|
+
Z: data["Z"],
|
|
129
|
+
Dref: data["D"],
|
|
130
|
+
Qref: data["Q"],
|
|
131
|
+
R: data["R"],
|
|
132
|
+
idx_i: data["idx_i"],
|
|
133
|
+
idx_j: data["idx_j"],
|
|
134
|
+
batch_seg: data["batch_seg"]
|
|
135
|
+
}
|
|
136
|
+
return feed_dict
|
|
137
|
+
|
|
138
|
+
#helper function to print errors
|
|
139
|
+
|
|
140
|
+
def output_est(sess, all_data, data_count):
|
|
141
|
+
with open(PNargs.yestfile,'w') as fy, open(PNargs.ygradxyzestfile,'wb') as fgrad:
|
|
142
|
+
line="%d\n\n" % PNargs.natom
|
|
143
|
+
for i in range(data_count):
|
|
144
|
+
data = all_data[i]
|
|
145
|
+
feed_dict = fill_feed_dict(data)
|
|
146
|
+
E_tmp, F_tmp = sess.run([energy, forces], feed_dict=feed_dict)
|
|
147
|
+
fy.write('%f\n' % E_tmp)
|
|
148
|
+
fgrad.write(line.encode('utf-8'))
|
|
149
|
+
np.savetxt(fgrad, -1*F_tmp, fmt='%20.12f', delimiter=" ")
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
#create tensorflow session
|
|
154
|
+
with tf.Session() as sess:
|
|
155
|
+
#restore latest checkpoint
|
|
156
|
+
checkpoint = tf.train.latest_checkpoint(best_dir)
|
|
157
|
+
assert checkpoint is not None
|
|
158
|
+
nn.restore(sess, checkpoint)
|
|
159
|
+
|
|
160
|
+
#calculate errors on test data
|
|
161
|
+
print(' ')
|
|
162
|
+
# print('##### ------------ Estimating ------------ #####')
|
|
163
|
+
|
|
164
|
+
start = time.time()
|
|
165
|
+
|
|
166
|
+
output_est(sess, data, len(data))
|
|
167
|
+
|
|
168
|
+
end = time.time()
|
|
169
|
+
hours, rem = divmod(end-start, 3600)
|
|
170
|
+
minutes, seconds = divmod(rem, 60)
|
|
171
|
+
|
|
172
|
+
# print(' ')
|
|
173
|
+
# print('--------------------------------------------------')
|
|
174
|
+
# print('Total CPU time for estimating - {:0>2}:{:0>2}:{:05.2f}'.format(int(hours),int(minutes),seconds))
|
|
175
|
+
# print('--------------------------------------------------')
|
|
176
|
+
# print(' ')
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
|