servalcat 0.4.131__cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.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.
- servalcat/__init__.py +10 -0
- servalcat/__main__.py +120 -0
- servalcat/ext.cpython-314t-x86_64-linux-gnu.so +0 -0
- servalcat/refine/__init__.py +0 -0
- servalcat/refine/cgsolve.py +100 -0
- servalcat/refine/refine.py +1162 -0
- servalcat/refine/refine_geom.py +245 -0
- servalcat/refine/refine_spa.py +400 -0
- servalcat/refine/refine_xtal.py +339 -0
- servalcat/refine/spa.py +151 -0
- servalcat/refine/xtal.py +312 -0
- servalcat/refmac/__init__.py +0 -0
- servalcat/refmac/exte.py +191 -0
- servalcat/refmac/refmac_keywords.py +660 -0
- servalcat/refmac/refmac_wrapper.py +423 -0
- servalcat/spa/__init__.py +0 -0
- servalcat/spa/fofc.py +488 -0
- servalcat/spa/fsc.py +391 -0
- servalcat/spa/localcc.py +197 -0
- servalcat/spa/realspcc_from_var.py +128 -0
- servalcat/spa/run_refmac.py +979 -0
- servalcat/spa/shift_maps.py +293 -0
- servalcat/spa/shiftback.py +137 -0
- servalcat/spa/translate.py +129 -0
- servalcat/utils/__init__.py +35 -0
- servalcat/utils/commands.py +1629 -0
- servalcat/utils/fileio.py +836 -0
- servalcat/utils/generate_operators.py +296 -0
- servalcat/utils/hkl.py +811 -0
- servalcat/utils/logger.py +140 -0
- servalcat/utils/maps.py +345 -0
- servalcat/utils/model.py +933 -0
- servalcat/utils/refmac.py +759 -0
- servalcat/utils/restraints.py +888 -0
- servalcat/utils/symmetry.py +298 -0
- servalcat/xtal/__init__.py +0 -0
- servalcat/xtal/french_wilson.py +262 -0
- servalcat/xtal/run_refmac_small.py +240 -0
- servalcat/xtal/sigmaa.py +1954 -0
- servalcat/xtal/twin.py +316 -0
- servalcat-0.4.131.dist-info/METADATA +60 -0
- servalcat-0.4.131.dist-info/RECORD +45 -0
- servalcat-0.4.131.dist-info/WHEEL +6 -0
- servalcat-0.4.131.dist-info/entry_points.txt +4 -0
- servalcat-0.4.131.dist-info/licenses/LICENSE +373 -0
|
@@ -0,0 +1,660 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Author: "Keitaro Yamashita, Garib N. Murshudov"
|
|
3
|
+
MRC Laboratory of Molecular Biology
|
|
4
|
+
|
|
5
|
+
This software is released under the
|
|
6
|
+
Mozilla Public License, version 2.0; see LICENSE.
|
|
7
|
+
"""
|
|
8
|
+
from __future__ import absolute_import, division, print_function, generators
|
|
9
|
+
from servalcat.utils import logger
|
|
10
|
+
from servalcat.utils import model as model_util
|
|
11
|
+
import gemmi
|
|
12
|
+
b_to_u = model_util.b_to_u
|
|
13
|
+
|
|
14
|
+
def parse_atom_spec(s, itk):
|
|
15
|
+
# s: list of keywords
|
|
16
|
+
ret = {}
|
|
17
|
+
while itk < len(s):
|
|
18
|
+
if s[itk].lower().startswith(("chai", "segm")):
|
|
19
|
+
ret["chain"] = s[itk+1]
|
|
20
|
+
itk += 2
|
|
21
|
+
elif s[itk].lower().startswith("resi"):
|
|
22
|
+
ret["resi"] = int(s[itk+1])
|
|
23
|
+
itk += 2
|
|
24
|
+
elif s[itk].lower().startswith("ins"):
|
|
25
|
+
ret["icode"] = s[itk+1] if s[itk+1] != "." else " "
|
|
26
|
+
itk += 2
|
|
27
|
+
elif s[itk].lower().startswith(("atom", "atna", "name")):
|
|
28
|
+
if s[itk+1] == "{":
|
|
29
|
+
idx_close = s[itk+1:].index("}") + itk + 1
|
|
30
|
+
ret["names"] = s[itk+2:idx_close]
|
|
31
|
+
itk = idx_close + 1
|
|
32
|
+
else:
|
|
33
|
+
ret["names"] = [s[itk+1]]
|
|
34
|
+
itk += 2
|
|
35
|
+
elif s[itk].lower().startswith("alt"):
|
|
36
|
+
ret["altloc"] = s[itk+1]
|
|
37
|
+
itk += 2
|
|
38
|
+
elif s[itk].lower().startswith("symm"):
|
|
39
|
+
ret["symm"] = s[itk+1][0].lower() == "y"
|
|
40
|
+
itk += 2
|
|
41
|
+
else:
|
|
42
|
+
break
|
|
43
|
+
|
|
44
|
+
return ret, itk
|
|
45
|
+
# parse_atom_spec()
|
|
46
|
+
|
|
47
|
+
def parse_from_to(s, itk):
|
|
48
|
+
# s: list of keywords
|
|
49
|
+
ret = {}
|
|
50
|
+
if not s[itk].lower().startswith("from"):
|
|
51
|
+
raise RuntimeError("invalid from_to instruction: {}".format(s))
|
|
52
|
+
|
|
53
|
+
if s[itk+1] == "*":
|
|
54
|
+
ret["ifirst"] = None # Refmac sets -9999
|
|
55
|
+
else:
|
|
56
|
+
ret["ifirst"] = int(s[itk+1])
|
|
57
|
+
|
|
58
|
+
if s[itk+2].lower() != "to":
|
|
59
|
+
ret["chain"] = s[itk+2]
|
|
60
|
+
assert s[itk+3].lower() == "to"
|
|
61
|
+
itk += 4
|
|
62
|
+
else:
|
|
63
|
+
itk += 3
|
|
64
|
+
|
|
65
|
+
if s[itk] == "*":
|
|
66
|
+
ret["ilast"] = None # Refmac sets 9999
|
|
67
|
+
else:
|
|
68
|
+
ret["ilast"] = int(s[itk])
|
|
69
|
+
|
|
70
|
+
if "chain" not in ret:
|
|
71
|
+
ret["chain"] = s[itk+1]
|
|
72
|
+
itk += 2
|
|
73
|
+
else:
|
|
74
|
+
itk += 2
|
|
75
|
+
|
|
76
|
+
return ret, itk
|
|
77
|
+
# parse_from_to()
|
|
78
|
+
|
|
79
|
+
def read_exte(s, raise_unknown=True):
|
|
80
|
+
# using the same variable names as used in read_extra_restraints.f
|
|
81
|
+
ret = dict(defaults={})
|
|
82
|
+
if not s: return ret
|
|
83
|
+
defs = ret["defaults"]
|
|
84
|
+
rest_flag_old = rest_flag = False
|
|
85
|
+
if s[0].lower().startswith("exte"):
|
|
86
|
+
if s[1].lower().startswith("gene"): return ret
|
|
87
|
+
elif s[1].lower().startswith("file"): # XXX not supported
|
|
88
|
+
file_ext_now = s[2]
|
|
89
|
+
elif s[1].lower().startswith("syma"): # symall
|
|
90
|
+
# refmac sets "n" by default if "syma" given - but it is not good!
|
|
91
|
+
defs["symall_block"] = "y" if s[2][0].lower() == "y" else "n"
|
|
92
|
+
if len(s) > 3 and s[3].lower().startswith("excl"): # exclude
|
|
93
|
+
defs["exclude_self_block"] = s[4].lower().startswith("self")
|
|
94
|
+
elif s[1].lower().startswith("typa"): # typeall
|
|
95
|
+
#type_default = 2
|
|
96
|
+
defs["type_default"] = max(0, min(2, int(s[2])))
|
|
97
|
+
elif s[1].lower().startswith("alph"): # alphall
|
|
98
|
+
defs["alpha_default"] = float(s[2])
|
|
99
|
+
elif s[1].lower().startswith("verb"): # verbose
|
|
100
|
+
defs["ext_verbose"] = s[2][0].lower() != "n" and not s[2].lower().startswith("off")
|
|
101
|
+
# print("External verbose is on, i.e.") ...
|
|
102
|
+
elif s[1].lower().startswith("weig"): # weight
|
|
103
|
+
itk = 2
|
|
104
|
+
while itk < len(s): # FIXME check out-of-bounds in s[]
|
|
105
|
+
if s[itk].lower().startswith("scal"):
|
|
106
|
+
itk += 1
|
|
107
|
+
if itk >= len(s): break
|
|
108
|
+
try:
|
|
109
|
+
defs["scale_sigma_dist"] = float(s[itk]) # scale_sigma_loc
|
|
110
|
+
itk += 1
|
|
111
|
+
continue
|
|
112
|
+
except ValueError:
|
|
113
|
+
pass
|
|
114
|
+
for k in ("angl", "tors", "chir", "plan", "dist", "inte"):
|
|
115
|
+
if s[itk].lower().startswith(k):
|
|
116
|
+
itk += 1
|
|
117
|
+
if itk >= len(s): break
|
|
118
|
+
try:
|
|
119
|
+
defs["scale_sigma_{}".format(k)] = float(s[itk])
|
|
120
|
+
itk += 1
|
|
121
|
+
break
|
|
122
|
+
except ValueError:
|
|
123
|
+
pass
|
|
124
|
+
elif s[itk].lower().startswith("sgmn"):
|
|
125
|
+
defs["sigma_min_loc"] = float(s[itk+1])
|
|
126
|
+
itk += 2
|
|
127
|
+
elif s[itk].lower().startswith("sgmx"):
|
|
128
|
+
defs["sigma_max_loc"] = float(s[itk+1])
|
|
129
|
+
itk += 2
|
|
130
|
+
else:
|
|
131
|
+
raise RuntimeError("Error==> EXTE keyword interpretation: {}".format(" ".join(s)))
|
|
132
|
+
elif s[1].lower().startswith(("miss", "unde")): # undefined
|
|
133
|
+
defs["ignore_undefined"] = s[2].lower().startswith("igno")
|
|
134
|
+
elif s[1].lower().startswith("hydr"): # hydrogen
|
|
135
|
+
defs["ignore_hydrogens"] = s[2].lower().startswith("igno")
|
|
136
|
+
elif s[1].lower().startswith("cut"): # TODO I think this should be parsed outside
|
|
137
|
+
ret["sd_ext_cut"] = float(s[2]) # as this affects everything (not only following blocks)
|
|
138
|
+
elif s[1].lower().startswith("dmax"):
|
|
139
|
+
defs["dist_max_external"] = float(s[2])
|
|
140
|
+
elif s[1].lower().startswith("dmin"):
|
|
141
|
+
defs["dist_min_external"] = float(s[2])
|
|
142
|
+
elif s[1].lower().startswith("use"):
|
|
143
|
+
defs["use_atoms"] = s[2][0].lower()
|
|
144
|
+
if defs["use_atoms"] not in ("a", "m", "h"):
|
|
145
|
+
logger.writeln("invalid exte use keyword: {}".format(s[2]))
|
|
146
|
+
defs["use_atoms"] = "a"
|
|
147
|
+
elif s[1].lower().startswith("conv"):
|
|
148
|
+
if s[2].lower().startswith("pref"):
|
|
149
|
+
defs["prefix_ch"] = s[3] # ???
|
|
150
|
+
elif s[1].lower().startswith(("dist", "plan", "chir", "angl", "inte", "tors")):
|
|
151
|
+
ret["rest_type"] = s[1][:4].lower()
|
|
152
|
+
itk = 2
|
|
153
|
+
iat = 0
|
|
154
|
+
ret["restr"] = {}
|
|
155
|
+
n_expect = dict(plan=0, dist=2, inte=2, angl=3).get(ret["rest_type"], 4)
|
|
156
|
+
ret["restr"]["specs"] = [None for _ in range(n_expect)]
|
|
157
|
+
while itk < len(s):
|
|
158
|
+
if s[itk].lower().startswith(("firs", "seco", "thir", "four", "next", "atre", "atin")):
|
|
159
|
+
iat = dict(firs=0, seco=1, thir=2, four=3).get(s[itk][:4].lower(), iat+1)
|
|
160
|
+
atoms, itk = parse_atom_spec(s, itk+1)
|
|
161
|
+
if ret["rest_type"] == "plan":
|
|
162
|
+
ret["restr"]["specs"].append(atoms)
|
|
163
|
+
else:
|
|
164
|
+
ret["restr"]["specs"][iat] = atoms
|
|
165
|
+
elif s[itk].lower().startswith("type"):
|
|
166
|
+
try:
|
|
167
|
+
ret["restr"]["itype_in"] = int(s[itk+1])
|
|
168
|
+
except ValueError:
|
|
169
|
+
ret["restr"]["itype_in"] = dict(o=0, f=2).get(s[itk+1][0].lower(), 1)
|
|
170
|
+
if not (0 <= ret["restr"]["itype_in"] <= 2):
|
|
171
|
+
logger.writeln("WARNING: wrong type is given. setting to 2.\n=> {}".format(" ".join(s)))
|
|
172
|
+
ret["restr"]["itype_in"] = 2
|
|
173
|
+
itk += 2
|
|
174
|
+
elif s[itk].lower().startswith("symm"): # only for distance and angle
|
|
175
|
+
ret["restr"]["symm_in"] = s[itk+1][0].lower() == "y"
|
|
176
|
+
itk += 2
|
|
177
|
+
else:
|
|
178
|
+
d = dict(valu="value", dmin="dmin", dmax="dmax", smin="smin_value", smax="smax_value",
|
|
179
|
+
sigm="sigma_value", alph="alpha_in", prob="prob_in")
|
|
180
|
+
k = s[itk][:4].lower()
|
|
181
|
+
if k in d:
|
|
182
|
+
ret["restr"][d[k]] = float(s[itk+1])
|
|
183
|
+
itk += 2
|
|
184
|
+
else:
|
|
185
|
+
logger.writeln("unrecognised key: {}\n=> {}".format(s[itk], " ".join(s)))
|
|
186
|
+
break
|
|
187
|
+
elif s[1].lower().startswith("stac"):
|
|
188
|
+
ret["rest_type"] = "stac"
|
|
189
|
+
ret["restr"] = {}
|
|
190
|
+
ret["restr"]["specs"] = [[] for _ in range(2)]
|
|
191
|
+
itk = 2
|
|
192
|
+
#if s[itk].lower().startswith("dist"):
|
|
193
|
+
ip = 0
|
|
194
|
+
while itk < len(s):
|
|
195
|
+
if s[itk].lower().startswith("plan"):
|
|
196
|
+
ip = int(s[itk+1])
|
|
197
|
+
itk += 2
|
|
198
|
+
if ip not in (1, 2):
|
|
199
|
+
raise RuntimeError("Problem with stacking instructions. Plane number can be 1 or 2.\n=> {}".format(" ".join(s)))
|
|
200
|
+
elif s[itk].lower().startswith(("firs", "next")):
|
|
201
|
+
atoms, itk = parse_atom_spec(s, itk+1)
|
|
202
|
+
ret["restr"]["specs"][ip-1] = atoms
|
|
203
|
+
elif s[itk].lower().startswith(("dist", "sddi", "angl", "sdan", "type")):
|
|
204
|
+
k = dict(dist="dist_id", sddi="dist_sd", angl="angle_id", sdan="angle_sd", type="type_r")[s[itk][:4].lower()]
|
|
205
|
+
ret["restr"][k] = float(s[itk+1]) if k != "type_r" else int(s[itk+1])
|
|
206
|
+
itk += 2
|
|
207
|
+
else:
|
|
208
|
+
logger.writeln("WARNING: unrecognised keyword: {}\n=> {}".format(s[itk], " ".join(s)))
|
|
209
|
+
itk += 1
|
|
210
|
+
elif s[1].lower().startswith(("harm", "spec")):
|
|
211
|
+
ret["rest_type"] = s[1][:4].lower() # in Refmac, irest_type = 1 if harm else 2
|
|
212
|
+
ret["restr"] = dict(rectype="", toler=0.5, sigma_t=0.5, sigma_u=2.0 * b_to_u, u_val_incl=False)
|
|
213
|
+
itk = 2
|
|
214
|
+
while itk < len(s):
|
|
215
|
+
if s[itk].lower().startswith("auto"):
|
|
216
|
+
ret["restr"]["rectype"] = "auto"
|
|
217
|
+
itk += 1
|
|
218
|
+
elif s[itk].lower().startswith("atin"):
|
|
219
|
+
ret["restr"]["rectype"] = "atom"
|
|
220
|
+
atoms, itk = parse_atom_spec(s, itk+1)
|
|
221
|
+
ret["restr"]["specs"] = [atoms]
|
|
222
|
+
elif s[itk].lower().startswith("resi"):
|
|
223
|
+
ret["restr"]["rectype"] = "resi"
|
|
224
|
+
fromto, itk = parse_from_to(s, itk+1)
|
|
225
|
+
ret["restr"]["specs"] = [fromto]
|
|
226
|
+
if s[itk].lower().startswith("atom"):
|
|
227
|
+
ret["restr"]["specs"][0]["atom"] = s[itk+1] # called atom_resi in Refmac
|
|
228
|
+
itk += 2
|
|
229
|
+
elif s[itk].lower().startswith("sigm"):
|
|
230
|
+
ret["restr"]["sigma_t"] = float(s[itk+1])
|
|
231
|
+
itk += 2
|
|
232
|
+
elif s[itk].lower().startswith("tole"):
|
|
233
|
+
ret["restr"]["toler"] = float(s[itk+1])
|
|
234
|
+
itk += 2
|
|
235
|
+
elif s[itk].lower().startswith(("uval", "bval")):
|
|
236
|
+
if len(s) > itk+1 and s[itk+1].lower().startswith("incl"):
|
|
237
|
+
ret["restr"]["u_val_incl"] = True
|
|
238
|
+
itk += 2
|
|
239
|
+
else:
|
|
240
|
+
ret["restr"]["u_val_incl"] = False
|
|
241
|
+
itk += 1
|
|
242
|
+
elif s[itk].lower().startswith(("sigb", "sigu")):
|
|
243
|
+
ret["restr"]["sigma_u"] = float(s[itk+1]) * b_to_u
|
|
244
|
+
itk += 2
|
|
245
|
+
else:
|
|
246
|
+
logger.writeln("WARNING: unrecognised keyword: {}\n=> {}".format(s[itk], " ".join(s)))
|
|
247
|
+
itk += 1
|
|
248
|
+
|
|
249
|
+
else:
|
|
250
|
+
msg = "unrecognized exte keyword: " + " ".join(s)
|
|
251
|
+
if raise_unknown:
|
|
252
|
+
raise RuntimeError(msg)
|
|
253
|
+
else:
|
|
254
|
+
logger.writeln(f"WARNING: {msg}")
|
|
255
|
+
return ret
|
|
256
|
+
# read_exte()
|
|
257
|
+
|
|
258
|
+
def read_ridge_params(l, r, raise_unknown=True):
|
|
259
|
+
s = l.split()
|
|
260
|
+
assert s[0].lower().startswith("ridg")
|
|
261
|
+
ntok = len(s)
|
|
262
|
+
if s[1].lower().startswith("dist") and ntok > 2:
|
|
263
|
+
if s[2].lower().startswith("with"):
|
|
264
|
+
r.setdefault("groups", []).append({})
|
|
265
|
+
#r["groups"][-1]["sigma"] = sigma_dist_r
|
|
266
|
+
#r["groups"][-1]["dmax"] = dmax_dist_r
|
|
267
|
+
itk = 3
|
|
268
|
+
while itk < ntok:
|
|
269
|
+
if s[itk].lower().startswith("chai"):
|
|
270
|
+
r["groups"][-1]["chain"] = s[itk+1]
|
|
271
|
+
itk += 2
|
|
272
|
+
elif s[itk].lower().startswith("resi"):
|
|
273
|
+
r["groups"][-1]["resi"] = (int(s[itk+1]), int(s[itk+2]))
|
|
274
|
+
itk += 3
|
|
275
|
+
elif s[itk].lower().startswith("sigm"):
|
|
276
|
+
v = float(s[itk+1])
|
|
277
|
+
if v < 0: v = 0.01
|
|
278
|
+
r["groups"][-1]["sigma"] = v
|
|
279
|
+
itk += 2
|
|
280
|
+
elif s[itk].lower().startswith("dmax"):
|
|
281
|
+
v = float(s[itk+1])
|
|
282
|
+
if v < 0: v = 4.2
|
|
283
|
+
r["groups"][-1]["dmax"] = v
|
|
284
|
+
itk += 2
|
|
285
|
+
elif s[2].lower().startswith("incl") and ntok > 3:
|
|
286
|
+
# a: ridge_dist_include_all
|
|
287
|
+
# h: ridge_dist_include_hbond
|
|
288
|
+
# m: ridge_dist_include_main
|
|
289
|
+
v = s[3][0].lower()
|
|
290
|
+
if v in ("a", "h", "m"): r["include"] = v
|
|
291
|
+
elif s[2].lower().startswith("sigm"):
|
|
292
|
+
v = float(s[3])
|
|
293
|
+
r["sigma"] = v if v > 0 else 0.01
|
|
294
|
+
elif s[2].lower().startswith("dmax"):
|
|
295
|
+
v = float(s[3])
|
|
296
|
+
r["dmax"] = v if v > 0 else 4.2
|
|
297
|
+
elif s[2].lower().startswith("inte") and ntok > 3:
|
|
298
|
+
r["interchain"] = s[3][0].lower() == "y"
|
|
299
|
+
elif s[2].lower().startswith("symm") and ntok > 3:
|
|
300
|
+
r["intersym"] = s[3][0].lower() == "y"
|
|
301
|
+
elif s[2].lower().startswith("long") and ntok > 3:
|
|
302
|
+
r["long_range"] = max(0, int(s[3])) # long_range_residue_gap
|
|
303
|
+
elif s[2].lower().startswith("shor") and ntok > 3:
|
|
304
|
+
r["short_range"] = max(0, int(s[3])) # short_range_residue_gap
|
|
305
|
+
elif s[2].lower().startswith("hydr"):
|
|
306
|
+
r["hydrogen"] = ntok < 4 or s[3][0].lower() == "i" # hydrogens_include
|
|
307
|
+
elif s[2].lower().startswith("side") and ntok > 3:
|
|
308
|
+
r["sidechain"] = s[3][0].lower() == "i" # rb_side_chain_include
|
|
309
|
+
elif s[2].lower().startswith("filt"):
|
|
310
|
+
r["bvalue_filter"] = True
|
|
311
|
+
if s[3].lower().startswith("bran"):
|
|
312
|
+
v = float(s[4])
|
|
313
|
+
r["bvalue_filter_range"] = v if v > 0 else 2.0
|
|
314
|
+
else:
|
|
315
|
+
msg = "unrecognised keyword: {}\n=> {}".format(s[2], l)
|
|
316
|
+
if raise_unknown:
|
|
317
|
+
raise RuntimeError(msg)
|
|
318
|
+
else:
|
|
319
|
+
logger.writeln(f"WARNING: {msg}")
|
|
320
|
+
elif s[1].lower().startswith(("atom", "posi")): # not used
|
|
321
|
+
r["sigma_pos"] = float(s[2]) if ntok > 2 else 0.1
|
|
322
|
+
elif s[1].lower().startswith(("bval", "uval")) and ntok > 2:
|
|
323
|
+
if s[2].lower().startswith("diff"):
|
|
324
|
+
itk = 3
|
|
325
|
+
while itk < ntok:
|
|
326
|
+
if s[itk].lower().startswith("sigm"):
|
|
327
|
+
if ntok > itk + 1:
|
|
328
|
+
r["sigma_uval_diff"] = float(s[itk+1])
|
|
329
|
+
itk += 2
|
|
330
|
+
else:
|
|
331
|
+
r["sigma_uval_diff"] = 0.025
|
|
332
|
+
itk += 1
|
|
333
|
+
elif s[itk].lower().startswith("dmax"):
|
|
334
|
+
if ntok > itk + 1:
|
|
335
|
+
r["dmax_uval_diff"] = float(s[itk+1])
|
|
336
|
+
itk += 2
|
|
337
|
+
else:
|
|
338
|
+
r["dmax_uval_diff"] = 4.2
|
|
339
|
+
itk += 1
|
|
340
|
+
elif s[itk].lower().startswith("dmwe"): # not used
|
|
341
|
+
if ntok > itk + 1:
|
|
342
|
+
r["dmax_uval_weight"] = float(s[itk+1]) * b_to_u
|
|
343
|
+
itk += 2
|
|
344
|
+
else:
|
|
345
|
+
r["dmax_uval_weight"] = 3.0
|
|
346
|
+
itk += 1
|
|
347
|
+
else:
|
|
348
|
+
itk += 1
|
|
349
|
+
else:
|
|
350
|
+
r["sigma_b"] = float(s[2])
|
|
351
|
+
r["sigma_u"] = float(s[2])
|
|
352
|
+
else:
|
|
353
|
+
msg = "unrecognised keyword: {}\n=> {}".format(s[1], l)
|
|
354
|
+
if raise_unknown:
|
|
355
|
+
raise RuntimeError(msg)
|
|
356
|
+
else:
|
|
357
|
+
logger.writeln(f"WARNING: {msg}")
|
|
358
|
+
|
|
359
|
+
return r
|
|
360
|
+
# read_ridge_params()
|
|
361
|
+
|
|
362
|
+
def read_occupancy_params(l, r, raise_unknown=True):
|
|
363
|
+
s = l.split()
|
|
364
|
+
if not s[0].lower().startswith("occu"):
|
|
365
|
+
return r
|
|
366
|
+
ntok = len(s)
|
|
367
|
+
r.setdefault("groups", {}) # {igr: [{selection}, {selection}, ..]}
|
|
368
|
+
r.setdefault("const", []) # [[is_comp, group_ids]]
|
|
369
|
+
r.setdefault("ncycle", 0) # 0 means no refine
|
|
370
|
+
if (ntok > 4 and
|
|
371
|
+
s[1].lower().startswith("grou") and
|
|
372
|
+
s[2].lower().startswith("id")):
|
|
373
|
+
igr = s[3]
|
|
374
|
+
gr = r["groups"].setdefault(igr, [])
|
|
375
|
+
gr.append({})
|
|
376
|
+
itk = 4
|
|
377
|
+
while itk < ntok:
|
|
378
|
+
if s[itk].lower().startswith(("chai", "segm")):
|
|
379
|
+
gr[-1]["chains"] = []
|
|
380
|
+
itk += 1
|
|
381
|
+
while itk < ntok and not s[itk].lower().startswith(("resi","atom","alt")):
|
|
382
|
+
gr[-1]["chains"].append(s[itk])
|
|
383
|
+
itk += 1
|
|
384
|
+
elif s[itk].lower().startswith("resi"):
|
|
385
|
+
if s[itk+1].lower().startswith("from"):
|
|
386
|
+
gr[-1]["resi_from"] = gemmi.SeqId(s[itk+2])
|
|
387
|
+
if s[itk+3].lower().startswith("to"):
|
|
388
|
+
gr[-1]["resi_to"] = gemmi.SeqId(s[itk+4])
|
|
389
|
+
itk += 5
|
|
390
|
+
else:
|
|
391
|
+
gr[-1]["resi"] = gemmi.SeqId(s[itk+1])
|
|
392
|
+
itk += 2
|
|
393
|
+
elif s[itk].lower().startswith("atom"):
|
|
394
|
+
gr[-1]["atom"] = s[itk+1]
|
|
395
|
+
itk += 2
|
|
396
|
+
elif s[itk].lower().startswith("alt"):
|
|
397
|
+
gr[-1]["alt"] = s[itk+1]
|
|
398
|
+
itk += 2
|
|
399
|
+
elif (ntok > 4 and
|
|
400
|
+
s[1].lower().startswith("grou") and
|
|
401
|
+
s[2].lower().startswith("alts")):
|
|
402
|
+
r["const"].append((s[3].lower().startswith("comp"), s[4:]))
|
|
403
|
+
elif ntok > 1 and s[1].lower().startswith("refi"):
|
|
404
|
+
if ntok > 3 and s[2].lower().startswith("ncyc"):
|
|
405
|
+
r["ncycle"] = max(int(s[3]), r["ncycle"])
|
|
406
|
+
elif r["ncycle"] == 0:
|
|
407
|
+
r["ncycle"] = 1 # default
|
|
408
|
+
elif raise_unknown:
|
|
409
|
+
raise RuntimeError("unrecognized keyword: " + l)
|
|
410
|
+
|
|
411
|
+
return r
|
|
412
|
+
# read_occupancy_params()
|
|
413
|
+
|
|
414
|
+
def read_restr_params(l, r, raise_unknown=True):
|
|
415
|
+
s = l.split()
|
|
416
|
+
|
|
417
|
+
def read_tors_params(itk):
|
|
418
|
+
ret = {"flag": True}
|
|
419
|
+
if s[itk].lower().startswith("none"): # remove all
|
|
420
|
+
ret["flag"] = False
|
|
421
|
+
itk += 1
|
|
422
|
+
elif s[itk].lower().startswith("resi"):
|
|
423
|
+
ret["residue"] = s[itk+1]
|
|
424
|
+
itk += 2
|
|
425
|
+
elif s[itk].lower().startswith("grou"):
|
|
426
|
+
ret["group"] = s[itk+1] # group_name_tors_restr_o
|
|
427
|
+
itk += 2
|
|
428
|
+
elif s[itk].lower().startswith("link"):
|
|
429
|
+
ret["link"] = s[itk+1] #link_name_tors_restr_o
|
|
430
|
+
itk += 2
|
|
431
|
+
else:
|
|
432
|
+
pass # raise error?
|
|
433
|
+
while itk < len(s):
|
|
434
|
+
if s[itk].lower().startswith("name"):
|
|
435
|
+
itk += 1
|
|
436
|
+
ret["tors_name"] = s[itk] # RES_NAME_TORS_NAME_O
|
|
437
|
+
elif s[itk].lower().startswith("valu"):
|
|
438
|
+
itk += 1
|
|
439
|
+
ret["tors_value"] = float(s[itk]) # RES_NAME_TORS_VALUE_O
|
|
440
|
+
elif s[itk].lower().startswith("sigm"):
|
|
441
|
+
itk += 1
|
|
442
|
+
ret["tors_sigma"] = float(s[itk]) # RES_NAME_TORS_SIGMA_O
|
|
443
|
+
elif s[itk].lower().startswith("peri"):
|
|
444
|
+
itk += 1
|
|
445
|
+
ret["tors_period"] = int(s[itk]) # RES_NAME_TORS_PERIOD_O
|
|
446
|
+
itk += 1
|
|
447
|
+
return ret, itk
|
|
448
|
+
# read_tors_params()
|
|
449
|
+
|
|
450
|
+
if not s[0].lower().startswith("rest"):
|
|
451
|
+
return r
|
|
452
|
+
if s[1].lower().startswith("excl"):
|
|
453
|
+
# restr_params.f90 subroutine exclude_restraints
|
|
454
|
+
#r["exclude"] = True
|
|
455
|
+
pass
|
|
456
|
+
elif s[1].lower().startswith("conf"): # not implemented in Refmac
|
|
457
|
+
pass
|
|
458
|
+
elif s[1].lower().startswith(("bp", "pair", "base")):
|
|
459
|
+
if s[2].lower().startswith("dist"):
|
|
460
|
+
r["plane_dist"] = True
|
|
461
|
+
else:
|
|
462
|
+
r["basepair"] = True
|
|
463
|
+
# TODO read dnarna_params.txt
|
|
464
|
+
elif s[1].lower().startswith("tors") and len(s) > 2:
|
|
465
|
+
itk = 2
|
|
466
|
+
if s[itk].lower().startswith("hydr"):
|
|
467
|
+
itk += 1
|
|
468
|
+
if s[itk].lower().startswith("incl"):
|
|
469
|
+
itk += 1
|
|
470
|
+
r["htors_restraint"] = True
|
|
471
|
+
if s[itk].lower().startswith("all"): # this is servalcat default for now
|
|
472
|
+
r["htors_restraint_type"] = "all"
|
|
473
|
+
elif s[itk].lower().startswith("sele"):
|
|
474
|
+
r["htors_restraint_type"] = "sele"
|
|
475
|
+
r["htors_restraint_list"] = s[itk+1:]
|
|
476
|
+
else:
|
|
477
|
+
itk += 1
|
|
478
|
+
r["htors_restraint"] = False
|
|
479
|
+
elif s[itk].lower().startswith("fbas"):
|
|
480
|
+
pass # set user_basepair_file
|
|
481
|
+
elif s[itk].lower().startswith("incl"):
|
|
482
|
+
tmp, itk = read_tors_params(itk+1)
|
|
483
|
+
r.setdefault("torsion_include", []).append(tmp)
|
|
484
|
+
elif s[itk].lower().startswith("excl"):
|
|
485
|
+
# Should warn if value/sigma/period given?
|
|
486
|
+
tmp, itk = read_tors_params(itk+1)
|
|
487
|
+
r.setdefault("torsion_exclude", []).append(tmp)
|
|
488
|
+
elif s[1].lower().startswith("resi"):
|
|
489
|
+
pass
|
|
490
|
+
elif s[1].lower().startswith("chir"):
|
|
491
|
+
pass
|
|
492
|
+
elif raise_unknown:
|
|
493
|
+
raise RuntimeError("unrecognized keyword: " + l)
|
|
494
|
+
# read_restr_params()
|
|
495
|
+
|
|
496
|
+
def read_make_params(l, r, raise_unknown=True):
|
|
497
|
+
# TODO: hout,ribo,valu,spec,form,sdmi,segi
|
|
498
|
+
s = l.split()
|
|
499
|
+
assert s[0].lower().startswith("make")
|
|
500
|
+
itk = 1
|
|
501
|
+
ntok = len(s)
|
|
502
|
+
# keyword, key, func, possible, default
|
|
503
|
+
keys = (("hydr", "hydr", lambda x: x[0].lower(), set("aynf"), "a"),
|
|
504
|
+
("hout", "hout", lambda x: x[0].lower() in ("y", "p"), (True, False), True),
|
|
505
|
+
("chec", "check", lambda x: "0" if x.lower().startswith(("none", "0"))
|
|
506
|
+
else ("n" if x.lower().startswith(("liga", "n"))
|
|
507
|
+
else ("y" if x.lower().startswith(("all", "y")) else None)),
|
|
508
|
+
set("0ny"), None), # no default
|
|
509
|
+
("newl", "newligand", lambda x: x.lower().startswith(("c", "y", "noex")), (True, False), False),
|
|
510
|
+
("buil", "build", lambda x: x[0].lower(), set("ny"), "n"),
|
|
511
|
+
("pept", "pept", lambda x: x[0].lower(), set("yn"), "y"),
|
|
512
|
+
("link", "link", lambda x: x[0].lower(), set("ynd0"), "y"),
|
|
513
|
+
("suga", "sugar", lambda x: x[0].lower(), set("ynds"), "y"),
|
|
514
|
+
#("conn", "conn", lambda x: x[0].lower(), set("nyd0"), "n"), # TODO read conn_tolerance? (make conn tole val)
|
|
515
|
+
("symm", "symm", lambda x: x[0].lower(), set("ync"), "y"),
|
|
516
|
+
("chai", "chain", lambda x: x[0].lower(), set("yn"), "y"),
|
|
517
|
+
("cisp", "cispept", lambda x: x[0].lower(), set("yn"), "y"),
|
|
518
|
+
("ss", "ss", lambda x: x[0].lower(), set("ydn"), "y"),
|
|
519
|
+
("exit", "exit", lambda x: x[0].lower() == "y", (True, False), True),
|
|
520
|
+
)
|
|
521
|
+
while itk < ntok:
|
|
522
|
+
found = False
|
|
523
|
+
for k, t, f, p, d in keys:
|
|
524
|
+
if s[itk].lower().startswith(k):
|
|
525
|
+
if itk + 1 < len(s):
|
|
526
|
+
r[t] = f(s[itk+1])
|
|
527
|
+
if r[t] not in p:
|
|
528
|
+
raise SystemExit("Invalid make instruction: {}".format(l))
|
|
529
|
+
itk += 2
|
|
530
|
+
elif d is not None:
|
|
531
|
+
r[t] = d # set default
|
|
532
|
+
itk += 1
|
|
533
|
+
else:
|
|
534
|
+
raise SystemExit("Invalid make instruction: {}".format(l))
|
|
535
|
+
break
|
|
536
|
+
else:
|
|
537
|
+
if raise_unknown:
|
|
538
|
+
raise RuntimeError("unrecognized keyword: " + l)
|
|
539
|
+
else:
|
|
540
|
+
itk += 1
|
|
541
|
+
return r
|
|
542
|
+
# read_make_params()
|
|
543
|
+
|
|
544
|
+
def parse_line(l, ret, raise_unknown=True):
|
|
545
|
+
s = l.split()
|
|
546
|
+
ntok = len(s)
|
|
547
|
+
if ntok == 0: return
|
|
548
|
+
if s[0].lower().startswith("exte"):
|
|
549
|
+
ret.setdefault("exte", []).append(read_exte(s, raise_unknown))
|
|
550
|
+
elif s[0].lower().startswith("make"):
|
|
551
|
+
read_make_params(l, ret.setdefault("make", {}), raise_unknown)
|
|
552
|
+
elif s[0].lower().startswith(("sour", "scat")):
|
|
553
|
+
k = s[1].lower()
|
|
554
|
+
if k.startswith("em"):
|
|
555
|
+
ret["source"] = "em"
|
|
556
|
+
elif k.startswith("e"):
|
|
557
|
+
ret["source"] = "ec"
|
|
558
|
+
elif k.startswith("n"):
|
|
559
|
+
ret["source"] = "ne"
|
|
560
|
+
else:
|
|
561
|
+
ret["source"] = "xr"
|
|
562
|
+
# TODO check mb, lamb
|
|
563
|
+
elif s[0].lower().startswith("refi"): # TODO support this. Note that only valid with hklin
|
|
564
|
+
ret.setdefault("refi", {})
|
|
565
|
+
itk = 1
|
|
566
|
+
while itk < ntok:
|
|
567
|
+
if s[itk].lower().startswith("type"):
|
|
568
|
+
if itk+1 < ntok and s[itk+1].lower().startswith("unre"):
|
|
569
|
+
ret["refi"]["type"] = "unre"
|
|
570
|
+
itk += 2
|
|
571
|
+
else:
|
|
572
|
+
itk += 1
|
|
573
|
+
elif s[0].lower().startswith("dist"):
|
|
574
|
+
try:
|
|
575
|
+
ret["wbond"] = float(s[1])
|
|
576
|
+
except:
|
|
577
|
+
pass
|
|
578
|
+
# TODO read sdex, excu, dele, dmxe, dmne
|
|
579
|
+
elif s[0].lower().startswith("ridg"):
|
|
580
|
+
read_ridge_params(l, ret.setdefault("ridge", {}), raise_unknown)
|
|
581
|
+
elif s[0].lower().startswith("occu"):
|
|
582
|
+
read_occupancy_params(l, ret.setdefault("occu", {}), raise_unknown)
|
|
583
|
+
elif s[0].lower().startswith("rest"):
|
|
584
|
+
read_restr_params(l, ret.setdefault("restr", {}), raise_unknown)
|
|
585
|
+
elif s[0].lower().startswith("angl") and ntok > 1:
|
|
586
|
+
ret["wangle"] = float(s[1])
|
|
587
|
+
elif s[0].lower().startswith("tors") and ntok > 1:
|
|
588
|
+
ret["wtors"] = float(s[1])
|
|
589
|
+
elif s[0].lower().startswith(("bfac", "temp", "bval")):
|
|
590
|
+
pass # TODO
|
|
591
|
+
elif s[0].lower().startswith("plan") and ntok > 1:
|
|
592
|
+
ret["wplane"] = float(s[1])
|
|
593
|
+
elif s[0].lower().startswith("chir") and ntok > 1:
|
|
594
|
+
ret["wchir"] = float(s[1])
|
|
595
|
+
# TODO read calp
|
|
596
|
+
elif s[0].lower().startswith(("vdwr", "vand", "nonb")) and ntok > 1:
|
|
597
|
+
itk = 1
|
|
598
|
+
try:
|
|
599
|
+
ret["wvdw"] = float(s[itk])
|
|
600
|
+
itk += 1
|
|
601
|
+
except ValueError:
|
|
602
|
+
pass
|
|
603
|
+
elif raise_unknown:
|
|
604
|
+
raise RuntimeError(f"unrecognized keyword: {l}")
|
|
605
|
+
# TODO read maxr, over, sigm, incr, chan, vdwc, excl
|
|
606
|
+
# parse_line()
|
|
607
|
+
|
|
608
|
+
def get_lines(lines, depth=0):
|
|
609
|
+
ret = []
|
|
610
|
+
cont = ""
|
|
611
|
+
for l in lines:
|
|
612
|
+
if "!" in l: l = l[:l.index("!")]
|
|
613
|
+
if "#" in l: l = l[:l.index("#")]
|
|
614
|
+
l = l.strip()
|
|
615
|
+
if not l: continue
|
|
616
|
+
if l[0] == "@":
|
|
617
|
+
f = l[1:]
|
|
618
|
+
try:
|
|
619
|
+
yield from get_lines(open(f).readlines(), depth+1)
|
|
620
|
+
except RuntimeError:
|
|
621
|
+
return
|
|
622
|
+
continue
|
|
623
|
+
if l.split()[-1] == "-":
|
|
624
|
+
cont += l[:l.rfind("-")] + " "
|
|
625
|
+
continue
|
|
626
|
+
if cont:
|
|
627
|
+
l = cont + l
|
|
628
|
+
cont = ""
|
|
629
|
+
if l.split()[0].lower().startswith("end"):
|
|
630
|
+
# refmac stops reading keywords when "exit" is seen in stdin or a file
|
|
631
|
+
# but won't do this from nested files
|
|
632
|
+
if depth == 1:
|
|
633
|
+
raise RuntimeError
|
|
634
|
+
break
|
|
635
|
+
yield l
|
|
636
|
+
# get_lines()
|
|
637
|
+
|
|
638
|
+
def update_params(ret, inputs, raise_unknown=True):
|
|
639
|
+
if not inputs:
|
|
640
|
+
return
|
|
641
|
+
for l in get_lines(inputs):
|
|
642
|
+
parse_line(l, ret, raise_unknown=raise_unknown)
|
|
643
|
+
# update_keywords()
|
|
644
|
+
|
|
645
|
+
def parse_keywords(inputs, raise_unknown=True):
|
|
646
|
+
ret = {"make":{}, "ridge":{}, "refi":{}}
|
|
647
|
+
update_params(ret, inputs, raise_unknown)
|
|
648
|
+
return ret
|
|
649
|
+
# parse_keywords()
|
|
650
|
+
|
|
651
|
+
if __name__ == "__main__":
|
|
652
|
+
import sys
|
|
653
|
+
import json
|
|
654
|
+
print("waiting for input")
|
|
655
|
+
ret = {} #{"make":{}, "ridge":{}, "refi":{}}
|
|
656
|
+
for l in get_lines(sys.stdin):
|
|
657
|
+
parse_line(l, ret)
|
|
658
|
+
print()
|
|
659
|
+
print("Parsed:")
|
|
660
|
+
print(json.dumps(ret, indent=1))
|