#!/bin/env python
import os
import re
[docs]def read_table(dir, pattern):
files = [f for f in os.listdir(dir) if f.startswith(pattern)]
if len(files) == 0:
return ([], '')
if len(files) != 1:
raise AssertionError('error: plugin found %d files' % len(files))
filename = files[0]
funcform = filename.split('.')[-1] # last component of filename
data = parse_json(os.path.join(dir, filename))
return (data, funcform)
[docs]def parse_json(f):
'''Read a JSON file f and return the parsed object.
Note: Comments are allowed in this JSON file, but only simple parsing is done.
That is, anything between a # and the end of line is considered a comment.
This code is not smart enough to understand quoted or escaped #.
Note that comments are not allowed in the JSON format.
'''
with open(f, 'r') as fin:
s = fin.read()
pat = re.compile(r'#.*$', re.MULTILINE)
s = pat.sub('', s)
null = None
true = True
false = False
return eval(s)
[docs]def assign_setup(param_list, nk, allowMultiTerm=False):
# nk = number of keys
# (2 for bond, 3 for angle, 4 for dihedral etc)
# assign_setup returns param_dict and param_regex
# if allowMultiTerm is False
# param_dict = { (k1,k2...knk): pset, ... }
# param_regex = [ [key, regex, pset], ... ]
# if allowMultiTerm is True:
# param_dict = { (k1,k2...knk): [pset1,pset2...psetn], ... }
# param_regex = [ [key, regex, [pset1,pset2...psetn]], ... ]
# pset1...psetn must occur on successive lines with the same key
# construct param_dict, a dictionary of parameters
param_dict = dict()
# construct param_regex, a list of parameters for patterns that contain "*"
param_regex = list()
rstar = re.compile(r'\*')
rhat = re.compile(r'\^')
if (allowMultiTerm):
lastterm = ()
for s in param_list:
dkey = tuple(s[:nk])
key = ' '.join(s[:nk])
if rstar.search(key) != None:
# key contains "*"; replace instances of "*" with "[^ ]*"
if (dkey == lastterm):
param_regex[-1][-1].append(s[nk:])
else:
key = rhat.sub(r'\\^', key) # make ^ meaningless
regex = re.compile('^' + rstar.sub(r'[^ ]*', key) + '$')
param_regex.append([key, regex, [s[nk:]]])
else:
if (dkey == lastterm):
param_dict[dkey].append(s[nk:])
else:
if dkey in param_dict and param_dict[dkey] != [s[nk:]]:
print(
"Warning: Overriding parameters for %s: %s -> %s" %
(str(dkey), str(param_dict[dkey]), str(s[nk:])))
param_dict[dkey] = [s[nk:]]
lastterm = dkey
else:
for s in param_list:
dkey = tuple(s[:nk])
key = ' '.join(s[:nk])
if rstar.search(key) != None:
# key contains "*"; replace instances of "*" with "[^ ]*"
key = rhat.sub(r'\\^', key) # make ^ meaningless
regex = re.compile('^' + rstar.sub(r'[^ ]*', key) + "$")
param_regex.append([key, regex, s[nk:]])
else:
if (dkey in param_dict and param_dict[dkey] != s[nk:]):
print("Warning: Overriding parameters for %s: %s -> %s" %
(str(dkey), str(param_dict[dkey]), str(s[nk:])))
param_dict[dkey] = s[nk:]
return param_dict, param_regex
[docs]def assign_bonded_params(param_list,
atom_list,
term_list,
not_found,
btype=0,
allowMultiTerm=False):
"""Return list with parameters assigned for each force field term.
For example:
out_stretch_list = assign_bonded_params(stretch, atom_list, bond_list)
"""
# make sure we have at least one term
if len(term_list) == 0:
return []
out_term_list = list()
# determine number of keys in term_list
# (2 for stretch, 3 for angle, 4 for dihedral)
nk = len(term_list[0])
param_dict, param_regex = assign_setup(param_list, nk, allowMultiTerm)
# match parameters (in list order, for the case of regex)
for b in term_list:
bx = [getattr(atom_list[bi - 1], "atypes")[btype] for bi in b]
# first try to find exact match
p = param_dict.get(tuple(bx))
if p == None:
bx.reverse()
p = param_dict.get(tuple(bx))
# now use regex
if p == None:
# When using regex, we need to stop at the first match,
# so we check forward and reverse terms simultaniously
aggregate = ' '.join(bx)
bx.reverse()
aggrev = ' '.join(bx)
for [key, regex, temp] in param_regex:
if (regex.match(aggregate) != None or
regex.match(aggrev) != None):
p = temp
#print ' Found term <%s> matches <%s>' % (aggregate, key)
break
if p == None:
if not_found == 'allow':
pass
elif not_found == 'warn':
print('Term <%s> not found for' % aggregate, b)
else:
print('Term <%s> not found for' % aggregate, b)
raise AssertionError('Aborting')
else:
out_term_list.append([b, p])
return out_term_list
[docs]def assign(match_me, param_dict, param_regex):
"""match_me = list to be matched
"""
# first try to find exact match
p = param_dict.get(tuple(match_me))
# now use regex (in list order)
if p == None:
aggregate = ' '.join(match_me)
for [key, regex, temp] in param_regex:
if regex.match(aggregate) != None:
#print 'Found term <%s> matches <%s>' % (aggregate, key)
p = temp
break
return p
[docs]def assign_phased(match_me, param_dict, param_regex):
"""match_me = list to be matched
"""
phase = 1
# first try to find exact match
p = param_dict.get(tuple(match_me))
if p == None:
phase = -1
match_me.reverse()
p = param_dict.get(tuple(match_me))
# now use regex
if p == None:
# When using regex, we need to stop at the first match,
# so we check forward and reverse terms simultaniously
aggrev = ' '.join(match_me)
match_me.reverse()
aggregate = ' '.join(match_me)
for [key, regex, temp] in param_regex:
if regex.match(aggregate) != None:
phase = 1
#print 'Found term <%s> matches <%s>' % (aggregate, key)
p = temp
break
elif regex.match(aggrev) != None:
phase = -1
#print 'Found term <%s> matches <%s>' % (aggrev, key)
p = temp
break
return (phase, p)