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
servalcat/refine/xtal.py
ADDED
|
@@ -0,0 +1,312 @@
|
|
|
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
|
+
import gemmi
|
|
10
|
+
import numpy
|
|
11
|
+
import json
|
|
12
|
+
import scipy.sparse
|
|
13
|
+
from servalcat.utils import logger
|
|
14
|
+
from servalcat.xtal import sigmaa
|
|
15
|
+
from servalcat import utils
|
|
16
|
+
from servalcat import ext
|
|
17
|
+
from servalcat.xtal.twin import find_twin_domains_from_data, estimate_twin_fractions_from_model, mlopt_twin_fractions
|
|
18
|
+
b_to_u = utils.model.b_to_u
|
|
19
|
+
u_to_b = utils.model.u_to_b
|
|
20
|
+
integr = sigmaa.integr
|
|
21
|
+
|
|
22
|
+
class LL_Xtal:
|
|
23
|
+
def __init__(self, hkldata, free, st, monlib, source="xray", mott_bethe=True,
|
|
24
|
+
use_solvent=0, use_in_est="all", use_in_target="all", twin=False, twin_mlalpha=False,
|
|
25
|
+
addends=None, addends2=None, is_int=None):
|
|
26
|
+
assert source in ("electron", "xray", "neutron", "custom")
|
|
27
|
+
self.source = source
|
|
28
|
+
self.mott_bethe = False if source != "electron" else mott_bethe
|
|
29
|
+
self.hkldata = hkldata
|
|
30
|
+
self.free = free
|
|
31
|
+
self.st = st
|
|
32
|
+
self.monlib = monlib
|
|
33
|
+
self.d_min_max = hkldata.d_min_max()
|
|
34
|
+
self.fc_labs = ["FC0"]
|
|
35
|
+
self.use_solvent = use_solvent
|
|
36
|
+
if use_solvent: # 0: no solvent, 1: use solvent, 2: non-binary solvent mask
|
|
37
|
+
self.fc_labs.append("FCbulk")
|
|
38
|
+
self.hkldata.df["FCbulk"] = 0j
|
|
39
|
+
self.use_non_binary_mask = use_solvent == 2
|
|
40
|
+
self.D_labs = ["D{}".format(i) for i in range(len(self.fc_labs))]
|
|
41
|
+
self.k_overall = numpy.ones(len(self.hkldata.df.index))
|
|
42
|
+
self.b_aniso = gemmi.SMat33d(0,0,0,0,0,0)
|
|
43
|
+
self.hkldata.df["k_aniso"] = 1.
|
|
44
|
+
self.use_in_est = use_in_est
|
|
45
|
+
self.use_in_target = use_in_target
|
|
46
|
+
self.ll = None
|
|
47
|
+
self.addends = addends
|
|
48
|
+
self.addends2 = addends2
|
|
49
|
+
self.scaling = sigmaa.LsqScale()
|
|
50
|
+
if twin:
|
|
51
|
+
self.twin_data, _ = find_twin_domains_from_data(self.hkldata)
|
|
52
|
+
else:
|
|
53
|
+
self.twin_data = None
|
|
54
|
+
self.twin_mlalpha = twin_mlalpha
|
|
55
|
+
if self.twin_data:
|
|
56
|
+
self.twin_data.setup_f_calc(len(self.fc_labs))
|
|
57
|
+
if is_int is None:
|
|
58
|
+
self.is_int = "I" in self.hkldata.df
|
|
59
|
+
else:
|
|
60
|
+
self.is_int = is_int
|
|
61
|
+
logger.writeln("will use {} reflections for parameter estimation".format(self.use_in_est))
|
|
62
|
+
logger.writeln("will use {} reflections for refinement".format(self.use_in_target))
|
|
63
|
+
|
|
64
|
+
def refine_id(self):
|
|
65
|
+
return {"xray": "X-RAY", "electron": "ELECTRON", "neutron": "NEUTRON", "custom": "CUSTOM"}.get(self.source, "") + " DIFFRACTION"
|
|
66
|
+
|
|
67
|
+
def update_ml_params(self):
|
|
68
|
+
self.b_aniso = sigmaa.determine_ml_params(self.hkldata, self.is_int, self.fc_labs, self.D_labs, self.b_aniso,
|
|
69
|
+
use=self.use_in_est,
|
|
70
|
+
twin_data=self.twin_data)#D_trans="splus", S_trans="splus")
|
|
71
|
+
self.hkldata.df["k_aniso"] = self.hkldata.debye_waller_factors(b_cart=self.b_aniso)
|
|
72
|
+
#determine_mlf_params_from_cc(self.hkldata, self.fc_labs, self.D_labs)
|
|
73
|
+
if self.twin_data and self.twin_mlalpha:
|
|
74
|
+
mlopt_twin_fractions(self.hkldata, self.twin_data, self.b_aniso)
|
|
75
|
+
def update_fc(self):
|
|
76
|
+
# modify st before fc calculation
|
|
77
|
+
b_resid = sigmaa.subtract_common_aniso_from_model([self.st])
|
|
78
|
+
self.b_aniso += gemmi.SMat33d(*b_resid.elements_pdb()) # needed for target calculation
|
|
79
|
+
d_min = max(self.twin_data.s2_array)**(-0.5) if self.twin_data else self.d_min_max[0]
|
|
80
|
+
sigmaa.update_fc(st_list=[self.st], fc_labs=self.fc_labs,
|
|
81
|
+
d_min=d_min, monlib=self.monlib,
|
|
82
|
+
source=self.source, mott_bethe=self.mott_bethe,
|
|
83
|
+
hkldata=self.hkldata, twin_data=self.twin_data,
|
|
84
|
+
addends=self.addends, addends2=self.addends2)
|
|
85
|
+
|
|
86
|
+
def prepare_target(self):
|
|
87
|
+
if self.twin_data:
|
|
88
|
+
if self.use_in_target == "all":
|
|
89
|
+
idxes = numpy.concatenate([sel[i] for i_bin, _ in self.hkldata.binned("ml")
|
|
90
|
+
for sel in self.hkldata.centric_and_selections["ml"][i_bin] for i in (1,2)])
|
|
91
|
+
else:
|
|
92
|
+
i = 1 if self.use_in_target == "work" else 2
|
|
93
|
+
idxes = numpy.concatenate([sel[i] for i_bin, _ in self.hkldata.binned("ml")
|
|
94
|
+
for sel in self.hkldata.centric_and_selections["ml"][i_bin]])
|
|
95
|
+
mask = numpy.empty(len(self.hkldata.df.index)) * numpy.nan
|
|
96
|
+
mask[idxes] = 1 / self.hkldata.debye_waller_factors(b_cart=self.b_aniso)[idxes]**2
|
|
97
|
+
self.twin_data.est_f_true(self.hkldata.df.I.to_numpy() * mask,
|
|
98
|
+
self.hkldata.df.SIGI.to_numpy() * mask)
|
|
99
|
+
self.k_ani2_inv_masked = mask
|
|
100
|
+
|
|
101
|
+
def _overall_scale(self, min_b=0.1):
|
|
102
|
+
miller_array = self.twin_data.asu if self.twin_data else self.hkldata.miller_array()
|
|
103
|
+
d_min = max(self.twin_data.s2_array)**(-0.5) if self.twin_data else self.d_min_max[0]
|
|
104
|
+
if self.use_solvent:
|
|
105
|
+
Fmask = sigmaa.calc_Fmask(self.st, d_min, miller_array, self.use_non_binary_mask)
|
|
106
|
+
if self.twin_data:
|
|
107
|
+
fc_sum = self.twin_data.f_calc[:,:-1].sum(axis=1)
|
|
108
|
+
else:
|
|
109
|
+
fc_sum = self.hkldata.df[self.fc_labs[:-1]].sum(axis=1).to_numpy()
|
|
110
|
+
fc_list = [fc_sum, Fmask]
|
|
111
|
+
else:
|
|
112
|
+
if self.twin_data:
|
|
113
|
+
fc_list = [self.twin_data.f_calc.sum(axis=1)]
|
|
114
|
+
else:
|
|
115
|
+
fc_list = [self.hkldata.df[self.fc_labs].sum(axis=1).to_numpy()]
|
|
116
|
+
self.scaling.set_data(self.hkldata, fc_list, self.is_int, sigma_cutoff=0, twin_data=self.twin_data)
|
|
117
|
+
self.scaling.scale()
|
|
118
|
+
self.b_aniso = self.scaling.b_aniso
|
|
119
|
+
b = self.scaling.b_iso
|
|
120
|
+
min_b_iso = self.st[0].calculate_b_aniso_range()[0] # actually min of aniso too
|
|
121
|
+
tmp = min_b_iso + b
|
|
122
|
+
if tmp < min_b: # perhaps better only adjust b_iso that went too small, but we need to recalculate Fc
|
|
123
|
+
logger.writeln(" Adjusting overall B to avoid too small value")
|
|
124
|
+
b += min_b - tmp
|
|
125
|
+
logger.writeln(" Applying overall B to model: {:.2f}".format(b))
|
|
126
|
+
utils.model.shift_b(self.st[0], b)
|
|
127
|
+
k_iso = self.hkldata.debye_waller_factors(b_iso=b)
|
|
128
|
+
self.hkldata.df["k_aniso"] = self.hkldata.debye_waller_factors(b_cart=self.b_aniso)
|
|
129
|
+
if self.use_solvent:
|
|
130
|
+
if self.twin_data:
|
|
131
|
+
s2 = numpy.asarray(self.twin_data.s2_array)
|
|
132
|
+
else:
|
|
133
|
+
s2 = 1. / self.hkldata.d_spacings().to_numpy()**2
|
|
134
|
+
Fbulk = Fmask * self.scaling.get_solvent_scale(self.scaling.k_sol, self.scaling.b_sol, s2)
|
|
135
|
+
if self.twin_data:
|
|
136
|
+
self.twin_data.f_calc[:,-1] = Fbulk
|
|
137
|
+
else:
|
|
138
|
+
self.hkldata.df[self.fc_labs[-1]] = Fbulk
|
|
139
|
+
if "I" in self.hkldata.df:
|
|
140
|
+
o_labs = self.hkldata.df.columns.intersection(["I", "SIGI",
|
|
141
|
+
"I(+)","SIGI(+)", "I(-)", "SIGI(-)"])
|
|
142
|
+
self.hkldata.df[o_labs] /= self.scaling.k_overall**2
|
|
143
|
+
if "FP" in self.hkldata.df:
|
|
144
|
+
o_labs = self.hkldata.df.columns.intersection(["FP", "SIGFP",
|
|
145
|
+
"F(+)","SIGF(+)", "F(-)", "SIGF(-)"])
|
|
146
|
+
self.hkldata.df[o_labs] /= self.scaling.k_overall
|
|
147
|
+
|
|
148
|
+
if self.twin_data:
|
|
149
|
+
self.twin_data.f_calc[:] *= self.twin_data.debye_waller_factors(b_iso=b)[:,None]
|
|
150
|
+
else:
|
|
151
|
+
for lab in self.fc_labs: self.hkldata.df[lab] *= k_iso
|
|
152
|
+
self.hkldata.df["FC"] = self.hkldata.df[self.fc_labs].sum(axis=1)
|
|
153
|
+
|
|
154
|
+
# for next cycle
|
|
155
|
+
self.scaling.k_overall = 1.
|
|
156
|
+
self.scaling.b_iso = 0.
|
|
157
|
+
# _overall_scale()
|
|
158
|
+
|
|
159
|
+
def overall_scale(self, min_b=0.1):
|
|
160
|
+
self._overall_scale(min_b)
|
|
161
|
+
if self.twin_data:
|
|
162
|
+
estimate_twin_fractions_from_model(self.twin_data, self.hkldata)
|
|
163
|
+
self._overall_scale(min_b)
|
|
164
|
+
# overall_scale()
|
|
165
|
+
|
|
166
|
+
def calc_target(self): # -LL target for MLF or MLI
|
|
167
|
+
ret = 0
|
|
168
|
+
if self.twin_data:
|
|
169
|
+
Io = self.hkldata.df.I.to_numpy() * self.k_ani2_inv_masked
|
|
170
|
+
sigIo = self.hkldata.df.SIGI.to_numpy() * self.k_ani2_inv_masked
|
|
171
|
+
self.twin_data.est_f_true(Io, sigIo)
|
|
172
|
+
ret = self.twin_data.ll(Io, sigIo)
|
|
173
|
+
else:
|
|
174
|
+
k_aniso = self.hkldata.debye_waller_factors(b_cart=self.b_aniso)
|
|
175
|
+
f = sigmaa.mli if self.is_int else sigmaa.mlf
|
|
176
|
+
for i_bin, _ in self.hkldata.binned("ml"):
|
|
177
|
+
if self.use_in_target == "all":
|
|
178
|
+
idxes = numpy.concatenate([sel[i] for sel in self.hkldata.centric_and_selections["ml"][i_bin] for i in (1,2)])
|
|
179
|
+
else:
|
|
180
|
+
i = 1 if self.use_in_target == "work" else 2
|
|
181
|
+
idxes = numpy.concatenate([sel[i] for sel in self.hkldata.centric_and_selections["ml"][i_bin]])
|
|
182
|
+
ret += f(self.hkldata.df,
|
|
183
|
+
self.fc_labs,
|
|
184
|
+
numpy.vstack([self.hkldata.df[lab].to_numpy()[idxes] for lab in self.D_labs]).T,
|
|
185
|
+
self.hkldata.df.S.to_numpy()[idxes],
|
|
186
|
+
k_aniso,
|
|
187
|
+
idxes)
|
|
188
|
+
return ret * 2 # friedel mates
|
|
189
|
+
# calc_target()
|
|
190
|
+
|
|
191
|
+
def calc_stats(self, bin_stats=False):
|
|
192
|
+
stats, overall = sigmaa.calc_r_and_cc(self.hkldata, self.twin_data)
|
|
193
|
+
ret = {"summary": overall}
|
|
194
|
+
ret["summary"]["-LL"] = self.calc_target()
|
|
195
|
+
if self.twin_data:
|
|
196
|
+
ret["twin_alpha"] = {op.as_hkl().triplet(): a
|
|
197
|
+
# ops does not include identity
|
|
198
|
+
for op, a in zip([gemmi.Op()]+self.twin_data.ops, self.twin_data.alphas)}
|
|
199
|
+
if bin_stats:
|
|
200
|
+
ret["bin_stats"] = stats
|
|
201
|
+
ret["ml"] = self.hkldata.binned_df["ml"].copy()
|
|
202
|
+
for lab in "R", "CC":
|
|
203
|
+
logger.writeln(" ".join("{} = {:.4f}".format(x, overall[x]) for x in overall if x.startswith(lab)))
|
|
204
|
+
if self.is_int:
|
|
205
|
+
logger.writeln("R1 is calculated for reflections with I/sigma>2.")
|
|
206
|
+
return ret
|
|
207
|
+
|
|
208
|
+
def calc_grad(self, refine_params, specs=None):
|
|
209
|
+
blur = utils.model.determine_blur_for_dencalc(self.st, self.d_min_max[0] / 3) # TODO need more work
|
|
210
|
+
logger.writeln("blur for deriv= {:.2f}".format(blur))
|
|
211
|
+
if self.twin_data:
|
|
212
|
+
Io = self.hkldata.df.I.to_numpy() * self.k_ani2_inv_masked
|
|
213
|
+
sigIo = self.hkldata.df.SIGI.to_numpy() * self.k_ani2_inv_masked
|
|
214
|
+
dll_dab, d2ll_dab2 = self.twin_data.ll_der_fc0(Io, sigIo)
|
|
215
|
+
dll_dab *= self.twin_data.debye_waller_factors(b_iso=-blur)
|
|
216
|
+
else:
|
|
217
|
+
dll_dab = numpy.zeros(len(self.hkldata.df.FC), dtype=numpy.complex128)
|
|
218
|
+
d2ll_dab2 = numpy.empty(len(self.hkldata.df.index))
|
|
219
|
+
d2ll_dab2[:] = numpy.nan
|
|
220
|
+
k_ani = self.hkldata.debye_waller_factors(b_cart=self.b_aniso)
|
|
221
|
+
for i_bin, _ in self.hkldata.binned("ml"):
|
|
222
|
+
for c, work, test in self.hkldata.centric_and_selections["ml"][i_bin]:
|
|
223
|
+
if self.use_in_target == "all":
|
|
224
|
+
cidxes = numpy.concatenate([work, test])
|
|
225
|
+
else:
|
|
226
|
+
cidxes = work if self.use_in_target == "work" else test
|
|
227
|
+
epsilon = self.hkldata.df.epsilon.to_numpy()[cidxes]
|
|
228
|
+
Fcs = numpy.vstack([self.hkldata.df[lab].to_numpy()[cidxes] for lab in self.fc_labs]).T
|
|
229
|
+
Ds = numpy.vstack([self.hkldata.df[lab].to_numpy()[cidxes] for lab in self.D_labs]).T
|
|
230
|
+
S = self.hkldata.df["S"].to_numpy()[cidxes]
|
|
231
|
+
Fc = (Ds * Fcs).sum(axis=1)
|
|
232
|
+
Fc_abs = numpy.abs(Fc)
|
|
233
|
+
expip = numpy.exp(1j * numpy.angle(Fc))
|
|
234
|
+
if self.is_int:
|
|
235
|
+
Io = self.hkldata.df.I.to_numpy()
|
|
236
|
+
sigIo = self.hkldata.df.SIGI.to_numpy()
|
|
237
|
+
to = Io[cidxes] / sigIo[cidxes] - sigIo[cidxes] / (c+1) / k_ani[cidxes]**2 / S / epsilon
|
|
238
|
+
tf = k_ani[cidxes] * Fc_abs / numpy.sqrt(sigIo[cidxes])
|
|
239
|
+
sig1 = k_ani[cidxes]**2 * epsilon * S / sigIo[cidxes]
|
|
240
|
+
k_num = numpy.repeat(0.5 if c == 0 else 0., to.size) # acentric:0.5, centric: 0.
|
|
241
|
+
r = ext.integ_J_ratio(k_num, k_num - 0.5, True, to, tf, sig1, numpy.repeat(c+1, to.size),
|
|
242
|
+
integr.exp2_threshold, integr.h, integr.N, integr.ewmax)
|
|
243
|
+
r *= numpy.sqrt(sigIo[cidxes]) / k_ani[cidxes]
|
|
244
|
+
g = (2-c) * (Fc_abs - r) / epsilon / S * Ds[:,0]
|
|
245
|
+
dll_dab[cidxes] = g * expip
|
|
246
|
+
#d2ll_dab2[cidxes] = (2-c)**2 / S / epsilon * Ds[0]**2 # approximation
|
|
247
|
+
#d2ll_dab2[cidxes] = ((2-c) / S / epsilon + ((2-c) * r / k_ani[cidxes] / epsilon / S)**2) * Ds[0]**2
|
|
248
|
+
d2ll_dab2[cidxes] = g**2
|
|
249
|
+
else:
|
|
250
|
+
Fo = self.hkldata.df.FP.to_numpy()[cidxes] / k_ani[cidxes]
|
|
251
|
+
SigFo = self.hkldata.df.SIGFP.to_numpy()[cidxes] / k_ani[cidxes]
|
|
252
|
+
if c == 0: # acentric
|
|
253
|
+
Sigma = 2 * SigFo**2 + epsilon * S
|
|
254
|
+
X = 2 * Fo * Fc_abs / Sigma
|
|
255
|
+
m = gemmi.bessel_i1_over_i0(X)
|
|
256
|
+
g = 2 * (Fc_abs - m * Fo) / Sigma * Ds[:,0] # XXX assuming 0 is atomic structure
|
|
257
|
+
dll_dab[cidxes] = g * expip
|
|
258
|
+
d2ll_dab2[cidxes] = (2 / Sigma - (1 - m / X - m**2) * (2 * Fo / Sigma)**2) * Ds[:,0]**2
|
|
259
|
+
else:
|
|
260
|
+
Sigma = SigFo**2 + epsilon * S
|
|
261
|
+
X = Fo * Fc_abs / Sigma
|
|
262
|
+
#X = X.astype(numpy.float64)
|
|
263
|
+
m = numpy.tanh(X)
|
|
264
|
+
g = (Fc_abs - m * Fo) / Sigma * Ds[:,0]
|
|
265
|
+
dll_dab[cidxes] = g * expip
|
|
266
|
+
d2ll_dab2[cidxes] = (1. / Sigma - (Fo / Sigma)**2 * (1. - m**2)) * Ds[:,0]**2
|
|
267
|
+
dll_dab *= self.hkldata.debye_waller_factors(b_iso=-blur)
|
|
268
|
+
|
|
269
|
+
if self.mott_bethe:
|
|
270
|
+
d2 = numpy.reciprocal(self.twin_data.s2_array) if self.twin_data else self.hkldata.d_spacings()**2
|
|
271
|
+
dll_dab *= d2 * gemmi.mott_bethe_const()
|
|
272
|
+
d2ll_dab2 *= gemmi.mott_bethe_const()**2
|
|
273
|
+
|
|
274
|
+
if not self.twin_data:
|
|
275
|
+
dll_dab *= self.hkldata.df.llweight
|
|
276
|
+
d2ll_dab2 *= self.hkldata.df.llweight
|
|
277
|
+
|
|
278
|
+
# we need V**2/n for gradient.
|
|
279
|
+
if self.twin_data:
|
|
280
|
+
dll_dab_den = utils.hkl.fft_map(self.hkldata.cell, self.hkldata.sg, self.twin_data.asu, data=dll_dab)
|
|
281
|
+
else:
|
|
282
|
+
dll_dab_den = self.hkldata.fft_map(data=dll_dab)
|
|
283
|
+
dll_dab_den.array[:] *= self.hkldata.cell.volume**2 / dll_dab_den.point_count
|
|
284
|
+
#asu = dll_dab_den.masked_asu()
|
|
285
|
+
#dll_dab_den.array[:] *= 1 - asu.mask_array # 0 to use
|
|
286
|
+
|
|
287
|
+
self.ll = ext.LL(self.st, refine_params, self.mott_bethe, self.addends)
|
|
288
|
+
self.ll.set_ncs([x.tr for x in self.st.ncs if not x.given])
|
|
289
|
+
if self.source == "custom":
|
|
290
|
+
self.ll.calc_grad_custom(dll_dab_den, blur)
|
|
291
|
+
elif self.source == "neutron":
|
|
292
|
+
self.ll.calc_grad_n92(dll_dab_den, blur)
|
|
293
|
+
else:
|
|
294
|
+
self.ll.calc_grad_it92(dll_dab_den, blur)
|
|
295
|
+
|
|
296
|
+
# second derivative
|
|
297
|
+
s_array = numpy.sqrt(self.twin_data.s2_array) if self.twin_data else 1./self.hkldata.d_spacings().to_numpy()
|
|
298
|
+
if self.source == "custom":
|
|
299
|
+
self.ll.make_fisher_table_diag_direct_custom(s_array, d2ll_dab2)
|
|
300
|
+
self.ll.fisher_diag_from_table_custom()
|
|
301
|
+
elif self.source == "neutron":
|
|
302
|
+
self.ll.make_fisher_table_diag_direct_n92(s_array, d2ll_dab2)
|
|
303
|
+
self.ll.fisher_diag_from_table_n92()
|
|
304
|
+
else:
|
|
305
|
+
self.ll.make_fisher_table_diag_direct_it92(s_array, d2ll_dab2)
|
|
306
|
+
self.ll.fisher_diag_from_table_it92()
|
|
307
|
+
#json.dump(dict(b=self.ll.table_bs, pp1=self.ll.pp1, bb=self.ll.bb),
|
|
308
|
+
# open("ll_fisher.json", "w"), indent=True)
|
|
309
|
+
#a, (b,c) = ll.fisher_for_coo()
|
|
310
|
+
#json.dump(([float(x) for x in a], ([int(x) for x in b], [int(x) for x in c])), open("fisher.json", "w"))
|
|
311
|
+
if specs is not None:
|
|
312
|
+
self.ll.spec_correction(specs)
|
|
File without changes
|
servalcat/refmac/exte.py
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
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
|
+
import gemmi
|
|
10
|
+
import numpy
|
|
11
|
+
from servalcat.utils import logger
|
|
12
|
+
from servalcat import ext
|
|
13
|
+
|
|
14
|
+
"""import line_profiler
|
|
15
|
+
profile = line_profiler.LineProfiler()
|
|
16
|
+
import atexit
|
|
17
|
+
atexit.register(profile.print_stats)
|
|
18
|
+
@profile"""
|
|
19
|
+
def read_external_restraints(params, st, geom):
|
|
20
|
+
# default or current values
|
|
21
|
+
defs = dict(symall_block=False, exclude_self_block=False, type_default=2, alpha_default=1.,
|
|
22
|
+
ext_verbose=False, scale_sigma_dist=1., scale_sigma_angl=1., scale_sigma_tors=1.,
|
|
23
|
+
scale_sigma_chir=1., scale_sigma_plan=1., scale_sigma_inte=1.,
|
|
24
|
+
sigma_min_loc=0., sigma_max_loc=100., ignore_undefined=False, ignore_hydrogens=True,
|
|
25
|
+
dist_max_external=numpy.inf, dist_min_external=-numpy.inf, use_atoms="a", prefix_ch=" ")
|
|
26
|
+
#exte = gemmi.ExternalRestraints(st)
|
|
27
|
+
extypes = dict(dist=ext.Geometry.Bond,
|
|
28
|
+
angl=ext.Geometry.Angle,
|
|
29
|
+
chir=ext.Geometry.Chirality,
|
|
30
|
+
tors=ext.Geometry.Torsion,
|
|
31
|
+
plan=ext.Geometry.Plane,
|
|
32
|
+
inte=ext.Geometry.Interval,
|
|
33
|
+
harm=ext.Geometry.Harmonic,
|
|
34
|
+
spec=ext.Geometry.Special,
|
|
35
|
+
stac=ext.Geometry.Stacking)
|
|
36
|
+
exlists = dict(dist=geom.bonds, angl=geom.angles, tors=geom.torsions,
|
|
37
|
+
chir=geom.chirs, plan=geom.planes, inte=geom.intervals,
|
|
38
|
+
stac=geom.stackings, harm=geom.harmonics, spec=geom.specials)
|
|
39
|
+
num_org = {x: len(exlists[x]) for x in exlists}
|
|
40
|
+
|
|
41
|
+
# XXX There may be duplication (same chain, resi, name, and alt) - we should give error?
|
|
42
|
+
lookup = {(cra.chain.name, cra.residue.seqid.num, cra.residue.seqid.icode,
|
|
43
|
+
cra.atom.name, cra.atom.altloc) : cra.atom for cra in st[0].all()}
|
|
44
|
+
|
|
45
|
+
# TODO main chain / side chain filtering
|
|
46
|
+
for r in params:
|
|
47
|
+
if not r: continue
|
|
48
|
+
defs.update(r["defaults"])
|
|
49
|
+
if "rest_type" not in r: continue
|
|
50
|
+
if r["rest_type"] not in extypes:
|
|
51
|
+
logger.writeln("Warning: unknown external restraint type: {}".format(r["rest_type"]))
|
|
52
|
+
continue
|
|
53
|
+
|
|
54
|
+
atoms = []
|
|
55
|
+
skip = False
|
|
56
|
+
for i, spec in enumerate(r["restr"].get("specs", [])):
|
|
57
|
+
if r["rest_type"] == "stac":
|
|
58
|
+
atoms.append([])
|
|
59
|
+
if "ifirst" in spec:
|
|
60
|
+
for chain in st[0]:
|
|
61
|
+
if chain.name != spec["chain"]: continue
|
|
62
|
+
for res in chain:
|
|
63
|
+
if spec["ifirst"] is not None and res.seqid.num < spec["ifirst"]: continue
|
|
64
|
+
if spec["ilast"] is not None and res.seqid.num > spec["ilast"]: continue
|
|
65
|
+
atoms.extend([a for a in res if spec.get("atom", "*") == "*" or a.name == spec["atom"]])
|
|
66
|
+
else:
|
|
67
|
+
for name in spec["names"]: # only same altloc allowed?
|
|
68
|
+
key = (spec["chain"], spec["resi"], spec.get("icode", " "),
|
|
69
|
+
name, spec.get("altloc", "\0"))
|
|
70
|
+
atom = lookup.get(key)
|
|
71
|
+
if atom is None:
|
|
72
|
+
if defs["ignore_undefined"]:
|
|
73
|
+
logger.writeln("Warning: atom not found: {}".format(key))
|
|
74
|
+
skip = True
|
|
75
|
+
continue
|
|
76
|
+
raise RuntimeError("Atom not found: {}".format(key))
|
|
77
|
+
if defs["ignore_hydrogens"] and atom.is_hydrogen():
|
|
78
|
+
logger.writeln("External restraints with hydrogen atoms will be ignored: {}".format(key))
|
|
79
|
+
if r["rest_type"] in ("dist", "angl", "tors", "inte"):
|
|
80
|
+
skip = True
|
|
81
|
+
continue
|
|
82
|
+
if r["rest_type"] == "stac":
|
|
83
|
+
atoms[i].append(atom)
|
|
84
|
+
else:
|
|
85
|
+
atoms.append(atom)
|
|
86
|
+
if skip or not atoms:
|
|
87
|
+
continue
|
|
88
|
+
if r["rest_type"] in ("spec", "harm"):
|
|
89
|
+
if r["restr"]["rectype"] == "auto":
|
|
90
|
+
assert r["rest_type"] == "spec"
|
|
91
|
+
atoms = [cra.atom for cra in st[0].all()]
|
|
92
|
+
for atom in atoms:
|
|
93
|
+
ex = extypes[r["rest_type"]](atom)
|
|
94
|
+
if r["rest_type"] == "spec":
|
|
95
|
+
# TODO check if it is on special position. using r["restr"]["toler"]
|
|
96
|
+
ex.sigma_t = r["restr"]["sigma_t"]
|
|
97
|
+
ex.sigma_u =r["restr"]["sigma_u"]
|
|
98
|
+
ex.u_val_incl = r["restr"]["u_val_incl"]
|
|
99
|
+
# ex.trans_t =
|
|
100
|
+
# ex.mat_u =
|
|
101
|
+
else:
|
|
102
|
+
ex.sigma = r["restr"]["sigma_t"]
|
|
103
|
+
exlists[r["rest_type"]].append(ex)
|
|
104
|
+
continue
|
|
105
|
+
elif r["rest_type"] == "plan":
|
|
106
|
+
ex = extypes[r["rest_type"]](atoms)
|
|
107
|
+
else:
|
|
108
|
+
ex = extypes[r["rest_type"]](*atoms)
|
|
109
|
+
if r["rest_type"] in ("dist", "angl", "chir", "tors"):
|
|
110
|
+
value = r["restr"]["value"]
|
|
111
|
+
sigma = r["restr"]["sigma_value"] / defs["scale_sigma_{}".format(r["rest_type"])]
|
|
112
|
+
if r["rest_type"] == "chir":
|
|
113
|
+
ex.value = value
|
|
114
|
+
ex.sigma = sigma
|
|
115
|
+
else:
|
|
116
|
+
if r["rest_type"] == "dist":
|
|
117
|
+
sigma = min(max(sigma, defs["sigma_min_loc"]), defs["sigma_max_loc"])
|
|
118
|
+
vals = (value, sigma, value, sigma) # nucleus
|
|
119
|
+
elif r["rest_type"] == "tors":
|
|
120
|
+
vals = (value, sigma, 1) # period. # Refmac does not seem to read it from instruction
|
|
121
|
+
else:
|
|
122
|
+
vals = (value, sigma)
|
|
123
|
+
ex.values.append(extypes[r["rest_type"]].Value(*vals))
|
|
124
|
+
|
|
125
|
+
if r["rest_type"] == "dist":
|
|
126
|
+
if not (defs["dist_min_external"] < r["restr"]["value"] < defs["dist_max_external"]):
|
|
127
|
+
continue
|
|
128
|
+
ex.alpha = r["restr"].get("alpha_in", defs["alpha_default"])
|
|
129
|
+
ex.type = r["restr"].get("itype_in", defs["type_default"])
|
|
130
|
+
symm1 = any([spec.get("symm") for spec in r["restr"]["specs"]]) # is it the intention?
|
|
131
|
+
if r["restr"].get("symm_in", defs["symall_block"]) or symm1:
|
|
132
|
+
asu = gemmi.Asu.Different if defs["exclude_self_block"] else gemmi.Asu.Any
|
|
133
|
+
ex.set_image(st.cell, asu)
|
|
134
|
+
#print("dist=", ex.alpha, ex.type, ex.values[-1].value, ex.values[-1].sigma, ex.sym_idx, ex.pbc_shift, ex.atoms)
|
|
135
|
+
elif r["rest_type"] == "angl":
|
|
136
|
+
if any(spec.get("symm") for spec in r["restr"]["specs"]):
|
|
137
|
+
asus = [gemmi.Asu.Different if r["restr"]["specs"][i].get("symm") else gemmi.Asu.Same
|
|
138
|
+
for i in range(3)]
|
|
139
|
+
if atoms[0].serial > atoms[2].serial:
|
|
140
|
+
asus = asus[::-1]
|
|
141
|
+
ex.set_images(st.cell, asus[0], asus[2])
|
|
142
|
+
#print("angl=", ex.values[-1].value, ex.values[-1].sigma, ex.atoms)
|
|
143
|
+
elif r["rest_type"] == "tors":
|
|
144
|
+
pass
|
|
145
|
+
#print("tors=", ex.values[-1].value, ex.values[-1].sigma, ex.atoms)
|
|
146
|
+
elif r["rest_type"] == "chir":
|
|
147
|
+
#print("chir=", ex.value, ex.sigma, ex.atoms)
|
|
148
|
+
ex.sign = gemmi.ChiralityType.Positive if ex.value > 0 else gemmi.ChiralityType.Negative
|
|
149
|
+
ex.value = abs(ex.value)
|
|
150
|
+
elif r["rest_type"] == "plan":
|
|
151
|
+
ex.sigma = r["restr"]["sigma_value"] / defs["scale_sigma_{}".format(r["rest_type"])]
|
|
152
|
+
#print("plan=", ex.sigma, ex.atoms)
|
|
153
|
+
elif r["rest_type"] == "inte":
|
|
154
|
+
dmin, dmax = r["restr"].get("dmin"), r["restr"].get("dmax")
|
|
155
|
+
smin, smax = r["restr"].get("smin"), r["restr"].get("smax")
|
|
156
|
+
if (smin,smax).count(None) == 2:
|
|
157
|
+
smin = smax = 0.05
|
|
158
|
+
else:
|
|
159
|
+
if smin is None: smin = smax
|
|
160
|
+
if smax is None: smax = smin
|
|
161
|
+
smin /= defs["scale_sigma_inte"]
|
|
162
|
+
smax /= defs["scale_sigma_inte"]
|
|
163
|
+
if (dmin,dmax).count(None) == 1:
|
|
164
|
+
if dmin is None: dmin = dmax
|
|
165
|
+
if dmax is None: dmax = dmin
|
|
166
|
+
ex.dmin = dmin
|
|
167
|
+
ex.dmax = dmax
|
|
168
|
+
ex.smin = smin
|
|
169
|
+
ex.smax = smax
|
|
170
|
+
symm1 = any(spec.get("symm") for spec in r["restr"]["specs"]) # not tested
|
|
171
|
+
if r["restr"].get("symm_in", defs["symall_block"]) or symm1:
|
|
172
|
+
asu = gemmi.Asu.Different if defs["exclude_self_block"] else gemmi.Asu.Any
|
|
173
|
+
ex.set_image(st.cell, asu)
|
|
174
|
+
#print("inte=", ex.dmin, ex.dmax, ex.smin, ex.smax, ex.atoms)
|
|
175
|
+
elif r["rest_type"] == "stac":
|
|
176
|
+
ex.dist = r["restr"]["dist_id"]
|
|
177
|
+
ex.sd_dist = r["restr"]["dist_sd"]
|
|
178
|
+
ex.angle = r["restr"].get("angle_id", 0.)
|
|
179
|
+
ex.sd_angle = r["restr"]["angle_sd"]
|
|
180
|
+
#print("stac=", ex.dist, ex.sd_dist, ex.angle, ex.sd_angle, ex.planes)
|
|
181
|
+
|
|
182
|
+
exlists[r["rest_type"]].append(ex)
|
|
183
|
+
|
|
184
|
+
logger.writeln("External restraints from Refmac instructions")
|
|
185
|
+
labs = dict(dist="distances", angl="angles", tors="torsions",
|
|
186
|
+
chir="chirals", plan="planes", inte="intervals",
|
|
187
|
+
stac="stackings", harm="harmonics", spec="special positions")
|
|
188
|
+
for lab in labs:
|
|
189
|
+
logger.writeln(" Number of {:18s} : {}".format(labs[lab], len(exlists[lab]) - num_org[lab]))
|
|
190
|
+
logger.writeln("")
|
|
191
|
+
# read_external_restraints()
|