servalcat 0.4.72__cp312-cp312-macosx_11_0_arm64.whl → 0.4.88__cp312-cp312-macosx_11_0_arm64.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.
Potentially problematic release.
This version of servalcat might be problematic. Click here for more details.
- servalcat/__init__.py +2 -2
- servalcat/ext.cpython-312-darwin.so +0 -0
- servalcat/refine/refine.py +28 -26
- servalcat/refine/refine_geom.py +8 -2
- servalcat/refine/refine_spa.py +21 -12
- servalcat/refine/refine_xtal.py +27 -8
- servalcat/refine/spa.py +3 -0
- servalcat/refine/xtal.py +142 -96
- servalcat/refmac/exte.py +7 -5
- servalcat/refmac/refmac_keywords.py +11 -9
- servalcat/refmac/refmac_wrapper.py +89 -54
- servalcat/spa/fofc.py +11 -0
- servalcat/spa/fsc.py +3 -1
- servalcat/spa/run_refmac.py +11 -1
- servalcat/utils/fileio.py +5 -2
- servalcat/utils/hkl.py +20 -8
- servalcat/utils/model.py +13 -0
- servalcat/utils/refmac.py +19 -0
- servalcat/utils/restraints.py +19 -9
- servalcat/xtal/french_wilson.py +34 -28
- servalcat/xtal/sigmaa.py +338 -130
- servalcat/xtal/twin.py +115 -0
- {servalcat-0.4.72.dist-info → servalcat-0.4.88.dist-info}/METADATA +3 -3
- servalcat-0.4.88.dist-info/RECORD +45 -0
- {servalcat-0.4.72.dist-info → servalcat-0.4.88.dist-info}/WHEEL +1 -1
- servalcat-0.4.72.dist-info/RECORD +0 -44
- {servalcat-0.4.72.dist-info → servalcat-0.4.88.dist-info}/entry_points.txt +0 -0
- {servalcat-0.4.72.dist-info → servalcat-0.4.88.dist-info}/licenses/LICENSE +0 -0
servalcat/refine/xtal.py
CHANGED
|
@@ -14,18 +14,18 @@ from servalcat.utils import logger
|
|
|
14
14
|
from servalcat.xtal import sigmaa
|
|
15
15
|
from servalcat import utils
|
|
16
16
|
from servalcat import ext
|
|
17
|
+
from servalcat.xtal.twin import find_twin_domains_from_data, estimate_twin_fractions_from_model
|
|
17
18
|
b_to_u = utils.model.b_to_u
|
|
18
19
|
u_to_b = utils.model.u_to_b
|
|
19
20
|
integr = sigmaa.integr
|
|
20
21
|
|
|
21
22
|
class LL_Xtal:
|
|
22
23
|
def __init__(self, hkldata, centric_and_selections, free, st, monlib, source="xray", mott_bethe=True,
|
|
23
|
-
use_solvent=False, use_in_est="all", use_in_target="all"):
|
|
24
|
+
use_solvent=False, use_in_est="all", use_in_target="all", twin=False):
|
|
24
25
|
assert source in ("electron", "xray", "neutron")
|
|
25
26
|
self.source = source
|
|
26
27
|
self.mott_bethe = False if source != "electron" else mott_bethe
|
|
27
28
|
self.hkldata = hkldata
|
|
28
|
-
self.is_int = "I" in self.hkldata.df
|
|
29
29
|
self.centric_and_selections = centric_and_selections
|
|
30
30
|
self.free = free
|
|
31
31
|
self.st = st
|
|
@@ -44,39 +44,58 @@ class LL_Xtal:
|
|
|
44
44
|
self.use_in_target = use_in_target
|
|
45
45
|
self.ll = None
|
|
46
46
|
self.scaling = sigmaa.LsqScale()
|
|
47
|
+
if twin:
|
|
48
|
+
self.twin_data = find_twin_domains_from_data(self.hkldata)
|
|
49
|
+
else:
|
|
50
|
+
self.twin_data = None
|
|
51
|
+
if self.twin_data:
|
|
52
|
+
self.twin_data.setup_f_calc(len(self.fc_labs))
|
|
53
|
+
self.is_int = "I" in self.hkldata.df
|
|
47
54
|
logger.writeln("will use {} reflections for parameter estimation".format(self.use_in_est))
|
|
48
55
|
logger.writeln("will use {} reflections for refinement".format(self.use_in_target))
|
|
49
56
|
|
|
50
57
|
def update_ml_params(self):
|
|
51
58
|
self.b_aniso = sigmaa.determine_ml_params(self.hkldata, self.is_int, self.fc_labs, self.D_labs, self.b_aniso,
|
|
52
|
-
|
|
53
|
-
)#D_trans="splus", S_trans="splus")
|
|
59
|
+
self.centric_and_selections, use=self.use_in_est,
|
|
60
|
+
twin_data=self.twin_data)#D_trans="splus", S_trans="splus")
|
|
54
61
|
self.hkldata.df["k_aniso"] = self.hkldata.debye_waller_factors(b_cart=self.b_aniso)
|
|
55
62
|
#determine_mlf_params_from_cc(self.hkldata, self.fc_labs, self.D_labs,
|
|
56
63
|
# self.centric_and_selections)
|
|
57
|
-
|
|
58
|
-
|
|
59
64
|
def update_fc(self):
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
st = self.st
|
|
65
|
+
sigmaa.update_fc(st_list=[self.st], fc_labs=self.fc_labs,
|
|
66
|
+
d_min=self.d_min, monlib=self.monlib,
|
|
67
|
+
source=self.source, mott_bethe=self.mott_bethe,
|
|
68
|
+
hkldata=self.hkldata, twin_data=self.twin_data)
|
|
65
69
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
def prepare_target(self):
|
|
71
|
+
if self.twin_data:
|
|
72
|
+
if self.use_in_target == "all":
|
|
73
|
+
idxes = numpy.concatenate([sel[i] for i_bin, _ in self.hkldata.binned()
|
|
74
|
+
for sel in self.centric_and_selections[i_bin] for i in (1,2)])
|
|
75
|
+
else:
|
|
76
|
+
i = 1 if self.use_in_target == "work" else 2
|
|
77
|
+
idxes = numpy.concatenate([sel[i] for i_bin, _ in self.hkldata.binned()
|
|
78
|
+
for sel in self.centric_and_selections[i_bin]])
|
|
79
|
+
mask = numpy.empty(len(self.hkldata.df.index)) * numpy.nan
|
|
80
|
+
mask[idxes] = 1 / self.hkldata.debye_waller_factors(b_cart=self.b_aniso)[idxes]**2
|
|
81
|
+
self.twin_data.est_f_true(self.hkldata.df.I * mask,
|
|
82
|
+
self.hkldata.df.SIGI * mask)
|
|
72
83
|
|
|
73
84
|
def overall_scale(self, min_b=0.1):
|
|
74
|
-
|
|
85
|
+
miller_array = self.twin_data.asu if self.twin_data else self.hkldata.miller_array()
|
|
75
86
|
if self.use_solvent:
|
|
76
|
-
Fmask = sigmaa.calc_Fmask(self.st, self.d_min
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
Fmask = sigmaa.calc_Fmask(self.st, self.d_min, miller_array)
|
|
88
|
+
if self.twin_data:
|
|
89
|
+
fc_sum = self.twin_data.f_calc[:,:-1].sum(axis=1)
|
|
90
|
+
else:
|
|
91
|
+
fc_sum = self.hkldata.df[self.fc_labs[:-1]].sum(axis=1).to_numpy()
|
|
92
|
+
fc_list = [fc_sum, Fmask]
|
|
93
|
+
else:
|
|
94
|
+
if twin_data:
|
|
95
|
+
fc_list = [self.twin_data.f_calc.sum(axis=1)]
|
|
96
|
+
else:
|
|
97
|
+
fc_list = [self.hkldata.df[self.fc_labs].sum(axis=1).to_numpy()]
|
|
98
|
+
self.scaling.set_data(self.hkldata, fc_list, self.is_int, sigma_cutoff=0, twin_data=self.twin_data)
|
|
80
99
|
self.scaling.scale()
|
|
81
100
|
self.b_aniso = self.scaling.b_aniso
|
|
82
101
|
b = self.scaling.b_iso
|
|
@@ -90,9 +109,15 @@ class LL_Xtal:
|
|
|
90
109
|
k_iso = self.hkldata.debye_waller_factors(b_iso=b)
|
|
91
110
|
self.hkldata.df["k_aniso"] = self.hkldata.debye_waller_factors(b_cart=self.b_aniso)
|
|
92
111
|
if self.use_solvent:
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
112
|
+
if self.twin_data:
|
|
113
|
+
s2 = numpy.asarray(self.twin_data.s2_array)
|
|
114
|
+
else:
|
|
115
|
+
s2 = 1. / self.hkldata.d_spacings().to_numpy()**2
|
|
116
|
+
Fbulk = Fmask * self.scaling.get_solvent_scale(self.scaling.k_sol, self.scaling.b_sol, s2)
|
|
117
|
+
if self.twin_data:
|
|
118
|
+
self.twin_data.f_calc[:,-1] = Fbulk
|
|
119
|
+
else:
|
|
120
|
+
self.hkldata.df[self.fc_labs[-1]] = Fbulk
|
|
96
121
|
if self.is_int:
|
|
97
122
|
o_labs = self.hkldata.df.columns.intersection(["I", "SIGI",
|
|
98
123
|
"I(+)","SIGI(+)", "I(-)", "SIGI(-)"])
|
|
@@ -102,103 +127,125 @@ class LL_Xtal:
|
|
|
102
127
|
"F(+)","SIGF(+)", "F(-)", "SIGF(-)"])
|
|
103
128
|
self.hkldata.df[o_labs] /= self.scaling.k_overall
|
|
104
129
|
|
|
105
|
-
|
|
106
|
-
|
|
130
|
+
if self.twin_data:
|
|
131
|
+
self.twin_data.f_calc[:] *= self.twin_data.debye_waller_factors(b_iso=b)[:,None]
|
|
132
|
+
else:
|
|
133
|
+
for lab in self.fc_labs: self.hkldata.df[lab] *= k_iso
|
|
134
|
+
self.hkldata.df["FC"] = self.hkldata.df[self.fc_labs].sum(axis=1)
|
|
107
135
|
|
|
108
136
|
# for next cycle
|
|
109
137
|
self.scaling.k_overall = 1.
|
|
110
138
|
self.scaling.b_iso = 0.
|
|
139
|
+
if self.twin_data:
|
|
140
|
+
estimate_twin_fractions_from_model(self.twin_data, self.hkldata)
|
|
111
141
|
# overall_scale()
|
|
112
142
|
|
|
113
143
|
def calc_target(self): # -LL target for MLF or MLI
|
|
114
144
|
ret = 0
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
145
|
+
if self.twin_data:
|
|
146
|
+
ret = self.twin_data.ll()
|
|
147
|
+
else:
|
|
148
|
+
k_aniso = self.hkldata.debye_waller_factors(b_cart=self.b_aniso)
|
|
149
|
+
f = sigmaa.mli if self.is_int else sigmaa.mlf
|
|
150
|
+
for i_bin, _ in self.hkldata.binned():
|
|
151
|
+
if self.use_in_target == "all":
|
|
152
|
+
idxes = numpy.concatenate([sel[i] for sel in self.centric_and_selections[i_bin] for i in (1,2)])
|
|
153
|
+
else:
|
|
154
|
+
i = 1 if self.use_in_target == "work" else 2
|
|
155
|
+
idxes = numpy.concatenate([sel[i] for sel in self.centric_and_selections[i_bin]])
|
|
156
|
+
ret += f(self.hkldata.df,
|
|
157
|
+
self.fc_labs,
|
|
158
|
+
numpy.vstack([self.hkldata.df[lab].to_numpy()[idxes] for lab in self.D_labs]).T,
|
|
159
|
+
self.hkldata.df.S.to_numpy()[idxes],
|
|
160
|
+
k_aniso,
|
|
161
|
+
idxes)
|
|
129
162
|
return ret * 2 # friedel mates
|
|
130
163
|
# calc_target()
|
|
131
164
|
|
|
132
165
|
def calc_stats(self, bin_stats=False):
|
|
133
|
-
stats, overall = sigmaa.calc_r_and_cc(self.hkldata, self.centric_and_selections)
|
|
166
|
+
stats, overall = sigmaa.calc_r_and_cc(self.hkldata, self.centric_and_selections, self.twin_data)
|
|
134
167
|
ret = {"summary": overall}
|
|
135
168
|
ret["summary"]["-LL"] = self.calc_target()
|
|
169
|
+
if self.twin_data:
|
|
170
|
+
ret["twin_alpha"] = self.twin_data.alphas
|
|
136
171
|
if bin_stats:
|
|
137
172
|
ret["bin_stats"] = stats
|
|
138
173
|
for lab in "R", "CC":
|
|
139
174
|
logger.writeln(" ".join("{} = {:.4f}".format(x, overall[x]) for x in overall if x.startswith(lab)))
|
|
175
|
+
if self.is_int:
|
|
176
|
+
logger.writeln("R1 is calculated for reflections with I/sigma>2.")
|
|
140
177
|
return ret
|
|
141
178
|
|
|
142
179
|
def calc_grad(self, atom_pos, refine_xyz, adp_mode, refine_occ, refine_h, specs=None):
|
|
143
|
-
dll_dab = numpy.zeros(len(self.hkldata.df.FC), dtype=numpy.complex128)
|
|
144
|
-
d2ll_dab2 = numpy.empty(len(self.hkldata.df.index))
|
|
145
|
-
d2ll_dab2[:] = numpy.nan
|
|
146
180
|
blur = utils.model.determine_blur_for_dencalc(self.st, self.d_min / 3) # TODO need more work
|
|
147
181
|
logger.writeln("blur for deriv= {:.2f}".format(blur))
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
Fc_abs = numpy.abs(Fc)
|
|
161
|
-
expip = numpy.exp(1j * numpy.angle(Fc))
|
|
162
|
-
if self.is_int:
|
|
163
|
-
Io = self.hkldata.df.I.to_numpy()
|
|
164
|
-
sigIo = self.hkldata.df.SIGI.to_numpy()
|
|
165
|
-
to = Io[cidxes] / sigIo[cidxes] - sigIo[cidxes] / (c+1) / k_ani[cidxes]**2 / S / epsilon
|
|
166
|
-
tf = k_ani[cidxes] * Fc_abs / numpy.sqrt(sigIo[cidxes])
|
|
167
|
-
sig1 = k_ani[cidxes]**2 * epsilon * S / sigIo[cidxes]
|
|
168
|
-
k_num = 0.5 if c == 0 else 0. # acentric:0.5, centric: 0.
|
|
169
|
-
r = ext.integ_J_ratio(k_num, k_num - 0.5, True, to, tf, sig1, c+1,
|
|
170
|
-
integr.exp2_threshold, integr.h, integr.N, integr.ewmax)
|
|
171
|
-
r *= numpy.sqrt(sigIo[cidxes]) / k_ani[cidxes]
|
|
172
|
-
g = (2-c) * (Fc_abs - r) / epsilon / S * Ds[:,0]
|
|
173
|
-
dll_dab[cidxes] = g * expip
|
|
174
|
-
#d2ll_dab2[cidxes] = (2-c)**2 / S / epsilon * Ds[0]**2 # approximation
|
|
175
|
-
#d2ll_dab2[cidxes] = ((2-c) / S / epsilon + ((2-c) * r / k_ani[cidxes] / epsilon / S)**2) * Ds[0]**2
|
|
176
|
-
d2ll_dab2[cidxes] = g**2
|
|
177
|
-
else:
|
|
178
|
-
Fo = self.hkldata.df.FP.to_numpy()[cidxes] / k_ani[cidxes]
|
|
179
|
-
SigFo = self.hkldata.df.SIGFP.to_numpy()[cidxes] / k_ani[cidxes]
|
|
180
|
-
if c == 0: # acentric
|
|
181
|
-
Sigma = 2 * SigFo**2 + epsilon * S
|
|
182
|
-
X = 2 * Fo * Fc_abs / Sigma
|
|
183
|
-
m = gemmi.bessel_i1_over_i0(X)
|
|
184
|
-
g = 2 * (Fc_abs - m * Fo) / Sigma * Ds[:,0] # XXX assuming 0 is atomic structure
|
|
185
|
-
dll_dab[cidxes] = g * expip
|
|
186
|
-
d2ll_dab2[cidxes] = (2 / Sigma - (1 - m / X - m**2) * (2 * Fo / Sigma)**2) * Ds[:,0]**2
|
|
182
|
+
if self.twin_data:
|
|
183
|
+
dll_dab, d2ll_dab2 = self.twin_data.ll_der_fc0()
|
|
184
|
+
dll_dab *= self.twin_data.debye_waller_factors(b_iso=-blur)
|
|
185
|
+
else:
|
|
186
|
+
dll_dab = numpy.zeros(len(self.hkldata.df.FC), dtype=numpy.complex128)
|
|
187
|
+
d2ll_dab2 = numpy.empty(len(self.hkldata.df.index))
|
|
188
|
+
d2ll_dab2[:] = numpy.nan
|
|
189
|
+
k_ani = self.hkldata.debye_waller_factors(b_cart=self.b_aniso)
|
|
190
|
+
for i_bin, _ in self.hkldata.binned():
|
|
191
|
+
for c, work, test in self.centric_and_selections[i_bin]:
|
|
192
|
+
if self.use_in_target == "all":
|
|
193
|
+
cidxes = numpy.concatenate([work, test])
|
|
187
194
|
else:
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
195
|
+
cidxes = work if self.use_in_target == "work" else test
|
|
196
|
+
epsilon = self.hkldata.df.epsilon.to_numpy()[cidxes]
|
|
197
|
+
Fcs = numpy.vstack([self.hkldata.df[lab].to_numpy()[cidxes] for lab in self.fc_labs]).T
|
|
198
|
+
Ds = numpy.vstack([self.hkldata.df[lab].to_numpy()[cidxes] for lab in self.D_labs]).T
|
|
199
|
+
S = self.hkldata.df["S"].to_numpy()[cidxes]
|
|
200
|
+
Fc = (Ds * Fcs).sum(axis=1)
|
|
201
|
+
Fc_abs = numpy.abs(Fc)
|
|
202
|
+
expip = numpy.exp(1j * numpy.angle(Fc))
|
|
203
|
+
if self.is_int:
|
|
204
|
+
Io = self.hkldata.df.I.to_numpy()
|
|
205
|
+
sigIo = self.hkldata.df.SIGI.to_numpy()
|
|
206
|
+
to = Io[cidxes] / sigIo[cidxes] - sigIo[cidxes] / (c+1) / k_ani[cidxes]**2 / S / epsilon
|
|
207
|
+
tf = k_ani[cidxes] * Fc_abs / numpy.sqrt(sigIo[cidxes])
|
|
208
|
+
sig1 = k_ani[cidxes]**2 * epsilon * S / sigIo[cidxes]
|
|
209
|
+
k_num = 0.5 if c == 0 else 0. # acentric:0.5, centric: 0.
|
|
210
|
+
r = ext.integ_J_ratio(k_num, k_num - 0.5, True, to, tf, sig1, c+1,
|
|
211
|
+
integr.exp2_threshold, integr.h, integr.N, integr.ewmax)
|
|
212
|
+
r *= numpy.sqrt(sigIo[cidxes]) / k_ani[cidxes]
|
|
213
|
+
g = (2-c) * (Fc_abs - r) / epsilon / S * Ds[:,0]
|
|
193
214
|
dll_dab[cidxes] = g * expip
|
|
194
|
-
d2ll_dab2[cidxes] = (
|
|
215
|
+
#d2ll_dab2[cidxes] = (2-c)**2 / S / epsilon * Ds[0]**2 # approximation
|
|
216
|
+
#d2ll_dab2[cidxes] = ((2-c) / S / epsilon + ((2-c) * r / k_ani[cidxes] / epsilon / S)**2) * Ds[0]**2
|
|
217
|
+
d2ll_dab2[cidxes] = g**2
|
|
218
|
+
else:
|
|
219
|
+
Fo = self.hkldata.df.FP.to_numpy()[cidxes] / k_ani[cidxes]
|
|
220
|
+
SigFo = self.hkldata.df.SIGFP.to_numpy()[cidxes] / k_ani[cidxes]
|
|
221
|
+
if c == 0: # acentric
|
|
222
|
+
Sigma = 2 * SigFo**2 + epsilon * S
|
|
223
|
+
X = 2 * Fo * Fc_abs / Sigma
|
|
224
|
+
m = gemmi.bessel_i1_over_i0(X)
|
|
225
|
+
g = 2 * (Fc_abs - m * Fo) / Sigma * Ds[:,0] # XXX assuming 0 is atomic structure
|
|
226
|
+
dll_dab[cidxes] = g * expip
|
|
227
|
+
d2ll_dab2[cidxes] = (2 / Sigma - (1 - m / X - m**2) * (2 * Fo / Sigma)**2) * Ds[:,0]**2
|
|
228
|
+
else:
|
|
229
|
+
Sigma = SigFo**2 + epsilon * S
|
|
230
|
+
X = Fo * Fc_abs / Sigma
|
|
231
|
+
#X = X.astype(numpy.float64)
|
|
232
|
+
m = numpy.tanh(X)
|
|
233
|
+
g = (Fc_abs - m * Fo) / Sigma * Ds[:,0]
|
|
234
|
+
dll_dab[cidxes] = g * expip
|
|
235
|
+
d2ll_dab2[cidxes] = (1. / Sigma - (Fo / (Sigma * numpy.cosh(X)))**2) * Ds[:,0]**2
|
|
236
|
+
dll_dab *= self.hkldata.debye_waller_factors(b_iso=-blur)
|
|
195
237
|
|
|
196
238
|
if self.mott_bethe:
|
|
197
|
-
|
|
239
|
+
d2 = 1 / self.twin_data.s2_array if self.twin_data else self.hkldata.d_spacings()**2
|
|
240
|
+
dll_dab *= d2 * gemmi.mott_bethe_const()
|
|
198
241
|
d2ll_dab2 *= gemmi.mott_bethe_const()**2
|
|
199
242
|
|
|
243
|
+
|
|
200
244
|
# we need V**2/n for gradient.
|
|
201
|
-
|
|
245
|
+
if self.twin_data:
|
|
246
|
+
dll_dab_den = utils.hkl.fft_map(self.hkldata.cell, self.hkldata.sg, self.twin_data.asu, data=dll_dab)
|
|
247
|
+
else:
|
|
248
|
+
dll_dab_den = self.hkldata.fft_map(data=dll_dab)
|
|
202
249
|
dll_dab_den.array[:] *= self.hkldata.cell.volume**2 / dll_dab_den.point_count
|
|
203
250
|
#asu = dll_dab_den.masked_asu()
|
|
204
251
|
#dll_dab_den.array[:] *= 1 - asu.mask_array # 0 to use
|
|
@@ -211,13 +258,12 @@ class LL_Xtal:
|
|
|
211
258
|
self.ll.calc_grad_it92(dll_dab_den, blur)
|
|
212
259
|
|
|
213
260
|
# second derivative
|
|
261
|
+
s_array = numpy.sqrt(self.twin_data.s2_array) if self.twin_data else 1./self.hkldata.d_spacings().to_numpy()
|
|
214
262
|
if self.source == "neutron":
|
|
215
|
-
self.ll.make_fisher_table_diag_direct_n92(
|
|
216
|
-
d2ll_dab2)
|
|
263
|
+
self.ll.make_fisher_table_diag_direct_n92(s_array, d2ll_dab2)
|
|
217
264
|
self.ll.fisher_diag_from_table_n92()
|
|
218
265
|
else:
|
|
219
|
-
self.ll.make_fisher_table_diag_direct_it92(
|
|
220
|
-
d2ll_dab2)
|
|
266
|
+
self.ll.make_fisher_table_diag_direct_it92(s_array, d2ll_dab2)
|
|
221
267
|
self.ll.fisher_diag_from_table_it92()
|
|
222
268
|
#json.dump(dict(b=ll.table_bs, pp1=ll.pp1, bb=ll.bb),
|
|
223
269
|
# open("ll_fisher.json", "w"), indent=True)
|
servalcat/refmac/exte.py
CHANGED
|
@@ -120,18 +120,20 @@ def read_external_restraints(params, st, geom):
|
|
|
120
120
|
if r["rest_type"] == "dist":
|
|
121
121
|
if not (defs["dist_min_external"] < r["restr"]["value"] < defs["dist_max_external"]):
|
|
122
122
|
continue
|
|
123
|
-
if ex.atoms[0].serial > ex.atoms[1].serial:
|
|
124
|
-
ex.atoms = ex.atoms[::-1]
|
|
125
123
|
ex.alpha = r["restr"].get("alpha_in", defs["alpha_default"])
|
|
126
124
|
ex.type = r["restr"].get("itype_in", defs["type_default"])
|
|
127
125
|
symm1 = any([spec.get("symm") for spec in r["restr"]["specs"]]) # is it the intention?
|
|
128
126
|
if r["restr"].get("symm_in", defs["symall_block"]) or symm1:
|
|
129
127
|
asu = gemmi.Asu.Different if defs["exclude_self_block"] else gemmi.Asu.Any
|
|
130
|
-
|
|
131
|
-
ex.set_image(im)
|
|
128
|
+
ex.set_image(st.cell, asu)
|
|
132
129
|
#print("dist=", ex.alpha, ex.type, ex.values[-1].value, ex.values[-1].sigma, ex.sym_idx, ex.pbc_shift, ex.atoms)
|
|
133
130
|
elif r["rest_type"] == "angl":
|
|
134
|
-
|
|
131
|
+
if any(spec.get("symm") for spec in r["restr"]["specs"]):
|
|
132
|
+
asus = [gemmi.Asu.Different if r["restr"]["specs"][i].get("symm") else gemmi.Asu.Same
|
|
133
|
+
for i in range(3)]
|
|
134
|
+
if atoms[0].serial > atoms[2].serial:
|
|
135
|
+
asus = asus[::-1]
|
|
136
|
+
ex.set_images(st.cell, asus[0], asus[2])
|
|
135
137
|
#print("angl=", ex.values[-1].value, ex.values[-1].sigma, ex.atoms)
|
|
136
138
|
elif r["rest_type"] == "tors":
|
|
137
139
|
pass
|
|
@@ -37,6 +37,7 @@ def parse_atom_spec(s, itk):
|
|
|
37
37
|
itk += 2
|
|
38
38
|
elif s[itk].lower().startswith("symm"):
|
|
39
39
|
ret["symm"] = s[itk+1][0].lower() == "y"
|
|
40
|
+
itk += 2
|
|
40
41
|
else:
|
|
41
42
|
break
|
|
42
43
|
|
|
@@ -167,10 +168,10 @@ def read_exte(s):
|
|
|
167
168
|
except ValueError:
|
|
168
169
|
ret["restr"]["itype_in"] = dict(o=0, f=2).get(s[itk+1][0].lower(), 1)
|
|
169
170
|
if not (0 <= ret["restr"]["itype_in"] <= 2):
|
|
170
|
-
logger.writeln("WARNING: wrong type is given. setting to 2.\n=> {}".format(
|
|
171
|
+
logger.writeln("WARNING: wrong type is given. setting to 2.\n=> {}".format(" ".join(s)))
|
|
171
172
|
ret["restr"]["itype_in"] = 2
|
|
172
173
|
itk += 2
|
|
173
|
-
elif s[itk].lower().startswith("symm"): # only for distance
|
|
174
|
+
elif s[itk].lower().startswith("symm"): # only for distance and angle
|
|
174
175
|
ret["restr"]["symm_in"] = s[itk+1][0].lower() == "y"
|
|
175
176
|
itk += 2
|
|
176
177
|
else:
|
|
@@ -181,7 +182,8 @@ def read_exte(s):
|
|
|
181
182
|
ret["restr"][d[k]] = float(s[itk+1])
|
|
182
183
|
itk += 2
|
|
183
184
|
else:
|
|
184
|
-
logger.writeln("unrecognised key: {}\n=> {}".format(s[itk],
|
|
185
|
+
logger.writeln("unrecognised key: {}\n=> {}".format(s[itk], " ".join(s)))
|
|
186
|
+
break
|
|
185
187
|
elif s[1].lower().startswith("stac"):
|
|
186
188
|
ret["rest_type"] = "stac"
|
|
187
189
|
ret["restr"] = {}
|
|
@@ -194,7 +196,7 @@ def read_exte(s):
|
|
|
194
196
|
ip = int(s[itk+1])
|
|
195
197
|
itk += 2
|
|
196
198
|
if ip not in (1, 2):
|
|
197
|
-
raise RuntimeError("Problem with stacking instructions. Plane number can be 1 or 2.\n=> {}".format(
|
|
199
|
+
raise RuntimeError("Problem with stacking instructions. Plane number can be 1 or 2.\n=> {}".format(" ".join(s)))
|
|
198
200
|
elif s[itk].lower().startswith(("firs", "next")):
|
|
199
201
|
atoms, itk = parse_atom_spec(s, itk+1)
|
|
200
202
|
ret["restr"]["specs"][ip-1] = atoms
|
|
@@ -203,7 +205,7 @@ def read_exte(s):
|
|
|
203
205
|
ret["restr"][k] = float(s[itk+1]) if k != "type_r" else int(s[itk+1])
|
|
204
206
|
itk += 2
|
|
205
207
|
else:
|
|
206
|
-
logger.writeln("WARNING: unrecognised keyword: {}\n=> {}".format(s[itk],
|
|
208
|
+
logger.writeln("WARNING: unrecognised keyword: {}\n=> {}".format(s[itk], " ".join(s)))
|
|
207
209
|
itk += 1
|
|
208
210
|
elif s[1].lower().startswith(("harm", "spec")):
|
|
209
211
|
ret["rest_type"] = s[1][:4].lower() # in Refmac, irest_type = 1 if harm else 2
|
|
@@ -241,11 +243,11 @@ def read_exte(s):
|
|
|
241
243
|
ret["restr"]["sigma_u"] = float(s[itk+1]) * b_to_u
|
|
242
244
|
itk += 2
|
|
243
245
|
else:
|
|
244
|
-
logger.writeln("WARNING: unrecognised keyword: {}\n=> {}".format(s[itk],
|
|
246
|
+
logger.writeln("WARNING: unrecognised keyword: {}\n=> {}".format(s[itk], " ".join(s)))
|
|
245
247
|
itk += 1
|
|
246
248
|
|
|
247
249
|
else:
|
|
248
|
-
logger.writeln("WARNING: cannot parse: {}".format(
|
|
250
|
+
logger.writeln("WARNING: cannot parse: {}".format(" ".join(s)))
|
|
249
251
|
return ret
|
|
250
252
|
# read_exte()
|
|
251
253
|
|
|
@@ -543,8 +545,8 @@ def parse_line(l, ret):
|
|
|
543
545
|
ret.setdefault("refi", {})
|
|
544
546
|
itk = 1
|
|
545
547
|
while itk < ntok:
|
|
546
|
-
if s[itk].startswith("type"):
|
|
547
|
-
if itk+1 < ntok and s[itk+1].startswith("unre"):
|
|
548
|
+
if s[itk].lower().startswith("type"):
|
|
549
|
+
if itk+1 < ntok and s[itk+1].lower().startswith("unre"):
|
|
548
550
|
ret["refi"]["type"] = "unre"
|
|
549
551
|
itk += 2
|
|
550
552
|
else:
|
|
@@ -11,10 +11,12 @@ import numpy
|
|
|
11
11
|
import json
|
|
12
12
|
import os
|
|
13
13
|
import sys
|
|
14
|
+
import io
|
|
14
15
|
import tempfile
|
|
15
16
|
import subprocess
|
|
16
17
|
import argparse
|
|
17
18
|
from collections import OrderedDict
|
|
19
|
+
import servalcat # for version
|
|
18
20
|
from servalcat.utils import logger
|
|
19
21
|
from servalcat.refmac import refmac_keywords
|
|
20
22
|
from servalcat import utils
|
|
@@ -64,7 +66,7 @@ def read_stdin(stdin):
|
|
|
64
66
|
|
|
65
67
|
def prepare_crd(st, crdout, ligand, make, monlib_path=None, h_pos="elec",
|
|
66
68
|
no_adjust_hydrogen_distances=False, fix_long_resnames=True,
|
|
67
|
-
keep_entities=False):
|
|
69
|
+
keep_entities=False, unre=False):
|
|
68
70
|
assert h_pos in ("elec", "nucl")
|
|
69
71
|
h_change = dict(a=gemmi.HydrogenChange.ReAddButWater,
|
|
70
72
|
y=gemmi.HydrogenChange.NoChange,
|
|
@@ -80,67 +82,87 @@ def prepare_crd(st, crdout, ligand, make, monlib_path=None, h_pos="elec",
|
|
|
80
82
|
if at.occ > 1: # XXX should I check special positions?
|
|
81
83
|
at.occ = 1.
|
|
82
84
|
|
|
83
|
-
|
|
85
|
+
refmac_fixes = utils.refmac.FixForRefmac()
|
|
86
|
+
if keep_entities:
|
|
87
|
+
refmac_fixes.store_res_labels(st)
|
|
88
|
+
else:
|
|
84
89
|
utils.model.setup_entities(st, clear=True, force_subchain_names=True, overwrite_entity_type=True)
|
|
85
|
-
# TODO read dictionary from xyzin (priority: user cif -> monlib -> xyzin
|
|
86
|
-
try:
|
|
87
|
-
monlib = utils.restraints.load_monomer_library(st,
|
|
88
|
-
monomer_dir=monlib_path,
|
|
89
|
-
cif_files=ligand,
|
|
90
|
-
stop_for_unknowns=not make.get("newligand"))
|
|
91
|
-
except RuntimeError as e:
|
|
92
|
-
raise SystemExit("Error: {}".format(e))
|
|
93
90
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
only_from = set()
|
|
98
|
-
if make_link == "y":
|
|
99
|
-
# add all links
|
|
100
|
-
add_found = True
|
|
101
|
-
elif make_ss == "y":
|
|
102
|
-
add_found = True
|
|
103
|
-
only_from.add("disulf")
|
|
91
|
+
if unre:
|
|
92
|
+
logger.writeln("Monomer library will not be loaded due to unrestrained refinement request")
|
|
93
|
+
monlib = gemmi.MonLib()
|
|
104
94
|
else:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
95
|
+
# TODO read dictionary from xyzin (priority: user cif -> monlib -> xyzin
|
|
96
|
+
try:
|
|
97
|
+
monlib = utils.restraints.load_monomer_library(st,
|
|
98
|
+
monomer_dir=monlib_path,
|
|
99
|
+
cif_files=ligand,
|
|
100
|
+
stop_for_unknowns=not make.get("newligand"))
|
|
101
|
+
except RuntimeError as e:
|
|
102
|
+
raise SystemExit("Error: {}".format(e))
|
|
103
|
+
|
|
104
|
+
use_cispeps = make.get("cispept", "y") != "y"
|
|
105
|
+
make_link = make.get("link", "n")
|
|
106
|
+
make_ss = make.get("ss", "y")
|
|
107
|
+
only_from = set()
|
|
108
|
+
if make_link == "y":
|
|
109
|
+
# add all links
|
|
110
|
+
add_found = True
|
|
111
|
+
elif make_ss == "y":
|
|
112
|
+
add_found = True
|
|
113
|
+
only_from.add("disulf")
|
|
114
|
+
else:
|
|
115
|
+
add_found = False
|
|
116
|
+
|
|
117
|
+
utils.restraints.fix_elements_in_model(monlib, st)
|
|
118
|
+
utils.restraints.find_and_fix_links(st, monlib, add_found=add_found,
|
|
119
|
+
find_metal_links=(make_link == "y"),
|
|
120
|
+
find_symmetry_related=False, add_only_from=only_from)
|
|
121
|
+
for con in st.connections:
|
|
122
|
+
if con.link_id not in ("?", "", "gap") and con.link_id not in monlib.links:
|
|
123
|
+
logger.writeln(" removing unknown link id ({}). Ad-hoc link will be generated.".format(con.link_id))
|
|
124
|
+
con.link_id = ""
|
|
113
125
|
|
|
114
|
-
refmac_fixes = utils.refmac.FixForRefmac()
|
|
115
126
|
max_seq_num = max([max(res.seqid.num for res in chain) for model in st for chain in model])
|
|
116
127
|
if max_seq_num > 9999:
|
|
117
128
|
logger.writeln("Max residue number ({}) exceeds 9999. Needs workaround.".format(max_seq_num))
|
|
118
|
-
|
|
129
|
+
sio = io.StringIO()
|
|
130
|
+
topo = gemmi.prepare_topology(st, monlib, warnings=sio, ignore_unknown_links=True)
|
|
119
131
|
refmac_fixes.fix_before_topology(st, topo,
|
|
120
132
|
fix_microheterogeneity=False,
|
|
121
133
|
fix_resimax=True,
|
|
122
134
|
fix_nonpolymer=False)
|
|
123
135
|
|
|
124
|
-
if
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
136
|
+
if unre:
|
|
137
|
+
# Refmac5 does not seem to do anything to hydrogen when unre regardless of "make hydr"
|
|
138
|
+
sio = io.StringIO()
|
|
139
|
+
topo = gemmi.prepare_topology(st, monlib, warnings=sio, ignore_unknown_links=True)
|
|
140
|
+
metal_kws = []
|
|
141
|
+
else:
|
|
142
|
+
if make.get("hydr") == "a": logger.writeln("(re)generating hydrogen atoms")
|
|
143
|
+
try:
|
|
144
|
+
topo, metal_kws = utils.restraints.prepare_topology(st, monlib, h_change=h_change, ignore_unknown_links=False,
|
|
145
|
+
check_hydrogen=(h_change==gemmi.HydrogenChange.NoChange),
|
|
146
|
+
use_cispeps=use_cispeps)
|
|
147
|
+
except RuntimeError as e:
|
|
148
|
+
raise SystemExit("Error: {}".format(e))
|
|
131
149
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
150
|
+
if make.get("hydr") != "n" and st[0].has_hydrogen():
|
|
151
|
+
if h_pos == "nucl" and (make.get("hydr") == "a" or not no_adjust_hydrogen_distances):
|
|
152
|
+
resnames = st[0].get_all_residue_names()
|
|
153
|
+
utils.restraints.check_monlib_support_nucleus_distances(monlib, resnames)
|
|
154
|
+
logger.writeln("adjusting hydrogen position to nucleus")
|
|
155
|
+
topo.adjust_hydrogen_distances(gemmi.Restraints.DistanceOf.Nucleus, default_scale=1.1)
|
|
156
|
+
elif h_pos == "elec" and make.get("hydr") == "y" and not no_adjust_hydrogen_distances:
|
|
157
|
+
logger.writeln("adjusting hydrogen position to electron cloud")
|
|
158
|
+
topo.adjust_hydrogen_distances(gemmi.Restraints.DistanceOf.ElectronCloud)
|
|
141
159
|
|
|
142
160
|
if fix_long_resnames: refmac_fixes.fix_long_resnames(st)
|
|
143
161
|
|
|
162
|
+
# remove "given" ncs matrices
|
|
163
|
+
# TODO write them back to the output files
|
|
164
|
+
st.ncs = gemmi.NcsOpList(x for x in st.ncs if not x.given)
|
|
165
|
+
|
|
144
166
|
# for safety
|
|
145
167
|
if "_entry.id" in st.info:
|
|
146
168
|
st.info["_entry.id"] = st.info["_entry.id"].replace(" ", "")
|
|
@@ -221,11 +243,22 @@ def modify_output(pdbout, cifout, fixes, hout, cispeps, keep_original_output=Fal
|
|
|
221
243
|
# should we check metals and put MetalC?
|
|
222
244
|
|
|
223
245
|
# fix entity (Refmac seems to make DNA non-polymer; as seen in 1fix)
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
246
|
+
if not fixes or not fixes.res_labels:
|
|
247
|
+
utils.model.setup_entities(st, clear=True, overwrite_entity_type=True, force_subchain_names=True)
|
|
248
|
+
for e in st.entities:
|
|
249
|
+
if not e.full_sequence and e.entity_type == gemmi.EntityType.Polymer and e.subchains:
|
|
250
|
+
rspan = st[0].get_subchain(e.subchains[0])
|
|
251
|
+
e.full_sequence = [r.name for r in rspan]
|
|
252
|
+
|
|
253
|
+
# fix label_seq_id
|
|
254
|
+
for chain in st[0]:
|
|
255
|
+
for res in chain:
|
|
256
|
+
res.label_seq = None
|
|
257
|
+
st.assign_label_seq_id()
|
|
258
|
+
|
|
259
|
+
# add servalcat version
|
|
260
|
+
if len(st.meta.software) > 0 and st.meta.software[-1].name == "refmac":
|
|
261
|
+
st.meta.software[-1].version += f" (refmacat {servalcat.__version__})"
|
|
229
262
|
|
|
230
263
|
suffix = ".org"
|
|
231
264
|
os.rename(cifout, cifout + suffix)
|
|
@@ -292,11 +325,12 @@ def main(args):
|
|
|
292
325
|
crdout = None
|
|
293
326
|
refmac_fixes = None
|
|
294
327
|
cispeps = []
|
|
295
|
-
|
|
328
|
+
unre = keywords["refi"].get("type") == "unre"
|
|
329
|
+
if xyzin is not None:
|
|
296
330
|
#tmpfd, crdout = tempfile.mkstemp(prefix="gemmi_", suffix=".crd") # TODO use dir=CCP4_SCR
|
|
297
331
|
#os.close(tmpfd)
|
|
298
332
|
st = utils.fileio.read_structure(xyzin)
|
|
299
|
-
if not st.cell.is_crystal():
|
|
333
|
+
if not st.cell.is_crystal() and not unre:
|
|
300
334
|
if args.auto_box_with_padding is not None:
|
|
301
335
|
st.cell = utils.model.box_from_model(st[0], args.auto_box_with_padding)
|
|
302
336
|
st.spacegroup_hm = "P 1"
|
|
@@ -309,7 +343,8 @@ def main(args):
|
|
|
309
343
|
refmac_fixes, metal_kws = prepare_crd(st, crdout, args.ligand, make=keywords["make"], monlib_path=args.monlib,
|
|
310
344
|
h_pos="nucl" if keywords.get("source")=="ne" else "elec",
|
|
311
345
|
no_adjust_hydrogen_distances=args.no_adjust_hydrogen_distances,
|
|
312
|
-
keep_entities=args.keep_entities
|
|
346
|
+
keep_entities=args.keep_entities,
|
|
347
|
+
unre=unre)
|
|
313
348
|
inputs = metal_kws + inputs # add metal exte first; otherwise it may be affected by user-defined inputs
|
|
314
349
|
opts["xyzin"] = crdout
|
|
315
350
|
cispeps = st.cispeps
|