servalcat 0.4.99__cp313-cp313-macosx_10_14_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.

Potentially problematic release.


This version of servalcat might be problematic. Click here for more details.

Files changed (45) hide show
  1. servalcat/__init__.py +10 -0
  2. servalcat/__main__.py +120 -0
  3. servalcat/ext.cpython-313-darwin.so +0 -0
  4. servalcat/refine/__init__.py +0 -0
  5. servalcat/refine/cgsolve.py +100 -0
  6. servalcat/refine/refine.py +906 -0
  7. servalcat/refine/refine_geom.py +233 -0
  8. servalcat/refine/refine_spa.py +366 -0
  9. servalcat/refine/refine_xtal.py +281 -0
  10. servalcat/refine/spa.py +144 -0
  11. servalcat/refine/xtal.py +276 -0
  12. servalcat/refmac/__init__.py +0 -0
  13. servalcat/refmac/exte.py +182 -0
  14. servalcat/refmac/refmac_keywords.py +639 -0
  15. servalcat/refmac/refmac_wrapper.py +395 -0
  16. servalcat/spa/__init__.py +0 -0
  17. servalcat/spa/fofc.py +479 -0
  18. servalcat/spa/fsc.py +385 -0
  19. servalcat/spa/localcc.py +188 -0
  20. servalcat/spa/realspcc_from_var.py +128 -0
  21. servalcat/spa/run_refmac.py +977 -0
  22. servalcat/spa/shift_maps.py +293 -0
  23. servalcat/spa/shiftback.py +137 -0
  24. servalcat/spa/translate.py +129 -0
  25. servalcat/utils/__init__.py +35 -0
  26. servalcat/utils/commands.py +1547 -0
  27. servalcat/utils/fileio.py +744 -0
  28. servalcat/utils/generate_operators.py +296 -0
  29. servalcat/utils/hkl.py +714 -0
  30. servalcat/utils/logger.py +140 -0
  31. servalcat/utils/maps.py +345 -0
  32. servalcat/utils/model.py +782 -0
  33. servalcat/utils/refmac.py +760 -0
  34. servalcat/utils/restraints.py +781 -0
  35. servalcat/utils/symmetry.py +295 -0
  36. servalcat/xtal/__init__.py +0 -0
  37. servalcat/xtal/french_wilson.py +258 -0
  38. servalcat/xtal/run_refmac_small.py +240 -0
  39. servalcat/xtal/sigmaa.py +1644 -0
  40. servalcat/xtal/twin.py +121 -0
  41. servalcat-0.4.99.dist-info/METADATA +55 -0
  42. servalcat-0.4.99.dist-info/RECORD +45 -0
  43. servalcat-0.4.99.dist-info/WHEEL +5 -0
  44. servalcat-0.4.99.dist-info/entry_points.txt +4 -0
  45. servalcat-0.4.99.dist-info/licenses/LICENSE +373 -0
@@ -0,0 +1,276 @@
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
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, centric_and_selections, free, st, monlib, source="xray", mott_bethe=True,
24
+ use_solvent=False, use_in_est="all", use_in_target="all", twin=False):
25
+ assert source in ("electron", "xray", "neutron")
26
+ self.source = source
27
+ self.mott_bethe = False if source != "electron" else mott_bethe
28
+ self.hkldata = hkldata
29
+ self.centric_and_selections = centric_and_selections
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:
37
+ self.fc_labs.append("FCbulk")
38
+ self.hkldata.df["FCbulk"] = 0j
39
+ self.D_labs = ["D{}".format(i) for i in range(len(self.fc_labs))]
40
+ self.k_overall = numpy.ones(len(self.hkldata.df.index))
41
+ self.b_aniso = None
42
+ self.hkldata.df["k_aniso"] = 1.
43
+ self.use_in_est = use_in_est
44
+ self.use_in_target = use_in_target
45
+ self.ll = None
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
54
+ logger.writeln("will use {} reflections for parameter estimation".format(self.use_in_est))
55
+ logger.writeln("will use {} reflections for refinement".format(self.use_in_target))
56
+
57
+ def refine_id(self):
58
+ return {"xray": "X-RAY", "electron": "ELECTRON", "neutron": "NEUTRON"}.get(self.source, "") + " DIFFRACTION"
59
+
60
+ def update_ml_params(self):
61
+ self.b_aniso = sigmaa.determine_ml_params(self.hkldata, self.is_int, self.fc_labs, self.D_labs, self.b_aniso,
62
+ self.centric_and_selections, use=self.use_in_est,
63
+ twin_data=self.twin_data)#D_trans="splus", S_trans="splus")
64
+ self.hkldata.df["k_aniso"] = self.hkldata.debye_waller_factors(b_cart=self.b_aniso)
65
+ #determine_mlf_params_from_cc(self.hkldata, self.fc_labs, self.D_labs,
66
+ # self.centric_and_selections)
67
+ def update_fc(self):
68
+ sigmaa.update_fc(st_list=[self.st], fc_labs=self.fc_labs,
69
+ d_min=self.d_min_max[0], monlib=self.monlib,
70
+ source=self.source, mott_bethe=self.mott_bethe,
71
+ hkldata=self.hkldata, twin_data=self.twin_data)
72
+
73
+ def prepare_target(self):
74
+ if self.twin_data:
75
+ if self.use_in_target == "all":
76
+ idxes = numpy.concatenate([sel[i] for i_bin, _ in self.hkldata.binned()
77
+ for sel in self.centric_and_selections[i_bin] for i in (1,2)])
78
+ else:
79
+ i = 1 if self.use_in_target == "work" else 2
80
+ idxes = numpy.concatenate([sel[i] for i_bin, _ in self.hkldata.binned()
81
+ for sel in self.centric_and_selections[i_bin]])
82
+ mask = numpy.empty(len(self.hkldata.df.index)) * numpy.nan
83
+ mask[idxes] = 1 / self.hkldata.debye_waller_factors(b_cart=self.b_aniso)[idxes]**2
84
+ self.twin_data.est_f_true(self.hkldata.df.I.to_numpy() * mask,
85
+ self.hkldata.df.SIGI.to_numpy() * mask)
86
+
87
+ def overall_scale(self, min_b=0.1):
88
+ miller_array = self.twin_data.asu if self.twin_data else self.hkldata.miller_array()
89
+ if self.use_solvent:
90
+ Fmask = sigmaa.calc_Fmask(self.st, self.d_min_max[0], miller_array)
91
+ if self.twin_data:
92
+ fc_sum = self.twin_data.f_calc[:,:-1].sum(axis=1)
93
+ else:
94
+ fc_sum = self.hkldata.df[self.fc_labs[:-1]].sum(axis=1).to_numpy()
95
+ fc_list = [fc_sum, Fmask]
96
+ else:
97
+ if twin_data:
98
+ fc_list = [self.twin_data.f_calc.sum(axis=1)]
99
+ else:
100
+ fc_list = [self.hkldata.df[self.fc_labs].sum(axis=1).to_numpy()]
101
+ self.scaling.set_data(self.hkldata, fc_list, self.is_int, sigma_cutoff=0, twin_data=self.twin_data)
102
+ self.scaling.scale()
103
+ self.b_aniso = self.scaling.b_aniso
104
+ b = self.scaling.b_iso
105
+ min_b_iso = self.st[0].calculate_b_aniso_range()[0] # actually min of aniso too
106
+ tmp = min_b_iso + b
107
+ if tmp < min_b: # perhaps better only adjust b_iso that went too small, but we need to recalculate Fc
108
+ logger.writeln(" Adjusting overall B to avoid too small value")
109
+ b += min_b - tmp
110
+ logger.writeln(" Applying overall B to model: {:.2f}".format(b))
111
+ utils.model.shift_b(self.st[0], b)
112
+ k_iso = self.hkldata.debye_waller_factors(b_iso=b)
113
+ self.hkldata.df["k_aniso"] = self.hkldata.debye_waller_factors(b_cart=self.b_aniso)
114
+ if self.use_solvent:
115
+ if self.twin_data:
116
+ s2 = numpy.asarray(self.twin_data.s2_array)
117
+ else:
118
+ s2 = 1. / self.hkldata.d_spacings().to_numpy()**2
119
+ Fbulk = Fmask * self.scaling.get_solvent_scale(self.scaling.k_sol, self.scaling.b_sol, s2)
120
+ if self.twin_data:
121
+ self.twin_data.f_calc[:,-1] = Fbulk
122
+ else:
123
+ self.hkldata.df[self.fc_labs[-1]] = Fbulk
124
+ if self.is_int:
125
+ o_labs = self.hkldata.df.columns.intersection(["I", "SIGI",
126
+ "I(+)","SIGI(+)", "I(-)", "SIGI(-)"])
127
+ self.hkldata.df[o_labs] /= self.scaling.k_overall**2
128
+ else:
129
+ o_labs = self.hkldata.df.columns.intersection(["FP", "SIGFP",
130
+ "F(+)","SIGF(+)", "F(-)", "SIGF(-)"])
131
+ self.hkldata.df[o_labs] /= self.scaling.k_overall
132
+
133
+ if self.twin_data:
134
+ self.twin_data.f_calc[:] *= self.twin_data.debye_waller_factors(b_iso=b)[:,None]
135
+ else:
136
+ for lab in self.fc_labs: self.hkldata.df[lab] *= k_iso
137
+ self.hkldata.df["FC"] = self.hkldata.df[self.fc_labs].sum(axis=1)
138
+
139
+ # for next cycle
140
+ self.scaling.k_overall = 1.
141
+ self.scaling.b_iso = 0.
142
+ if self.twin_data:
143
+ estimate_twin_fractions_from_model(self.twin_data, self.hkldata)
144
+ # overall_scale()
145
+
146
+ def calc_target(self): # -LL target for MLF or MLI
147
+ ret = 0
148
+ if self.twin_data:
149
+ ret = self.twin_data.ll()
150
+ else:
151
+ k_aniso = self.hkldata.debye_waller_factors(b_cart=self.b_aniso)
152
+ f = sigmaa.mli if self.is_int else sigmaa.mlf
153
+ for i_bin, _ in self.hkldata.binned():
154
+ if self.use_in_target == "all":
155
+ idxes = numpy.concatenate([sel[i] for sel in self.centric_and_selections[i_bin] for i in (1,2)])
156
+ else:
157
+ i = 1 if self.use_in_target == "work" else 2
158
+ idxes = numpy.concatenate([sel[i] for sel in self.centric_and_selections[i_bin]])
159
+ ret += f(self.hkldata.df,
160
+ self.fc_labs,
161
+ numpy.vstack([self.hkldata.df[lab].to_numpy()[idxes] for lab in self.D_labs]).T,
162
+ self.hkldata.df.S.to_numpy()[idxes],
163
+ k_aniso,
164
+ idxes)
165
+ return ret * 2 # friedel mates
166
+ # calc_target()
167
+
168
+ def calc_stats(self, bin_stats=False):
169
+ stats, overall = sigmaa.calc_r_and_cc(self.hkldata, self.centric_and_selections, self.twin_data)
170
+ ret = {"summary": overall}
171
+ ret["summary"]["-LL"] = self.calc_target()
172
+ if self.twin_data:
173
+ ret["twin_alpha"] = self.twin_data.alphas
174
+ if bin_stats:
175
+ ret["bin_stats"] = stats
176
+ for lab in "R", "CC":
177
+ logger.writeln(" ".join("{} = {:.4f}".format(x, overall[x]) for x in overall if x.startswith(lab)))
178
+ if self.is_int:
179
+ logger.writeln("R1 is calculated for reflections with I/sigma>2.")
180
+ return ret
181
+
182
+ def calc_grad(self, atom_pos, refine_xyz, adp_mode, refine_occ, refine_h, specs=None):
183
+ blur = utils.model.determine_blur_for_dencalc(self.st, self.d_min_max[0] / 3) # TODO need more work
184
+ logger.writeln("blur for deriv= {:.2f}".format(blur))
185
+ if self.twin_data:
186
+ dll_dab, d2ll_dab2 = self.twin_data.ll_der_fc0()
187
+ dll_dab *= self.twin_data.debye_waller_factors(b_iso=-blur)
188
+ else:
189
+ dll_dab = numpy.zeros(len(self.hkldata.df.FC), dtype=numpy.complex128)
190
+ d2ll_dab2 = numpy.empty(len(self.hkldata.df.index))
191
+ d2ll_dab2[:] = numpy.nan
192
+ k_ani = self.hkldata.debye_waller_factors(b_cart=self.b_aniso)
193
+ for i_bin, _ in self.hkldata.binned():
194
+ for c, work, test in self.centric_and_selections[i_bin]:
195
+ if self.use_in_target == "all":
196
+ cidxes = numpy.concatenate([work, test])
197
+ else:
198
+ cidxes = work if self.use_in_target == "work" else test
199
+ epsilon = self.hkldata.df.epsilon.to_numpy()[cidxes]
200
+ Fcs = numpy.vstack([self.hkldata.df[lab].to_numpy()[cidxes] for lab in self.fc_labs]).T
201
+ Ds = numpy.vstack([self.hkldata.df[lab].to_numpy()[cidxes] for lab in self.D_labs]).T
202
+ S = self.hkldata.df["S"].to_numpy()[cidxes]
203
+ Fc = (Ds * Fcs).sum(axis=1)
204
+ Fc_abs = numpy.abs(Fc)
205
+ expip = numpy.exp(1j * numpy.angle(Fc))
206
+ if self.is_int:
207
+ Io = self.hkldata.df.I.to_numpy()
208
+ sigIo = self.hkldata.df.SIGI.to_numpy()
209
+ to = Io[cidxes] / sigIo[cidxes] - sigIo[cidxes] / (c+1) / k_ani[cidxes]**2 / S / epsilon
210
+ tf = k_ani[cidxes] * Fc_abs / numpy.sqrt(sigIo[cidxes])
211
+ sig1 = k_ani[cidxes]**2 * epsilon * S / sigIo[cidxes]
212
+ k_num = numpy.repeat(0.5 if c == 0 else 0., to.size) # acentric:0.5, centric: 0.
213
+ r = ext.integ_J_ratio(k_num, k_num - 0.5, True, to, tf, sig1, numpy.repeat(c+1, to.size),
214
+ integr.exp2_threshold, integr.h, integr.N, integr.ewmax)
215
+ r *= numpy.sqrt(sigIo[cidxes]) / k_ani[cidxes]
216
+ g = (2-c) * (Fc_abs - r) / epsilon / S * Ds[:,0]
217
+ dll_dab[cidxes] = g * expip
218
+ #d2ll_dab2[cidxes] = (2-c)**2 / S / epsilon * Ds[0]**2 # approximation
219
+ #d2ll_dab2[cidxes] = ((2-c) / S / epsilon + ((2-c) * r / k_ani[cidxes] / epsilon / S)**2) * Ds[0]**2
220
+ d2ll_dab2[cidxes] = g**2
221
+ else:
222
+ Fo = self.hkldata.df.FP.to_numpy()[cidxes] / k_ani[cidxes]
223
+ SigFo = self.hkldata.df.SIGFP.to_numpy()[cidxes] / k_ani[cidxes]
224
+ if c == 0: # acentric
225
+ Sigma = 2 * SigFo**2 + epsilon * S
226
+ X = 2 * Fo * Fc_abs / Sigma
227
+ m = gemmi.bessel_i1_over_i0(X)
228
+ g = 2 * (Fc_abs - m * Fo) / Sigma * Ds[:,0] # XXX assuming 0 is atomic structure
229
+ dll_dab[cidxes] = g * expip
230
+ d2ll_dab2[cidxes] = (2 / Sigma - (1 - m / X - m**2) * (2 * Fo / Sigma)**2) * Ds[:,0]**2
231
+ else:
232
+ Sigma = SigFo**2 + epsilon * S
233
+ X = Fo * Fc_abs / Sigma
234
+ #X = X.astype(numpy.float64)
235
+ m = numpy.tanh(X)
236
+ g = (Fc_abs - m * Fo) / Sigma * Ds[:,0]
237
+ dll_dab[cidxes] = g * expip
238
+ d2ll_dab2[cidxes] = (1. / Sigma - (Fo / (Sigma * numpy.cosh(X)))**2) * Ds[:,0]**2
239
+ dll_dab *= self.hkldata.debye_waller_factors(b_iso=-blur)
240
+
241
+ if self.mott_bethe:
242
+ d2 = 1 / self.twin_data.s2_array if self.twin_data else self.hkldata.d_spacings()**2
243
+ dll_dab *= d2 * gemmi.mott_bethe_const()
244
+ d2ll_dab2 *= gemmi.mott_bethe_const()**2
245
+
246
+
247
+ # we need V**2/n for gradient.
248
+ if self.twin_data:
249
+ dll_dab_den = utils.hkl.fft_map(self.hkldata.cell, self.hkldata.sg, self.twin_data.asu, data=dll_dab)
250
+ else:
251
+ dll_dab_den = self.hkldata.fft_map(data=dll_dab)
252
+ dll_dab_den.array[:] *= self.hkldata.cell.volume**2 / dll_dab_den.point_count
253
+ #asu = dll_dab_den.masked_asu()
254
+ #dll_dab_den.array[:] *= 1 - asu.mask_array # 0 to use
255
+
256
+ self.ll = ext.LL(self.st, atom_pos, self.mott_bethe, refine_xyz, adp_mode, refine_occ, refine_h)
257
+ self.ll.set_ncs([x.tr for x in self.st.ncs if not x.given])
258
+ if self.source == "neutron":
259
+ self.ll.calc_grad_n92(dll_dab_den, blur)
260
+ else:
261
+ self.ll.calc_grad_it92(dll_dab_den, blur)
262
+
263
+ # second derivative
264
+ s_array = numpy.sqrt(self.twin_data.s2_array) if self.twin_data else 1./self.hkldata.d_spacings().to_numpy()
265
+ if self.source == "neutron":
266
+ self.ll.make_fisher_table_diag_direct_n92(s_array, d2ll_dab2)
267
+ self.ll.fisher_diag_from_table_n92()
268
+ else:
269
+ self.ll.make_fisher_table_diag_direct_it92(s_array, d2ll_dab2)
270
+ self.ll.fisher_diag_from_table_it92()
271
+ #json.dump(dict(b=ll.table_bs, pp1=ll.pp1, bb=ll.bb),
272
+ # open("ll_fisher.json", "w"), indent=True)
273
+ #a, (b,c) = ll.fisher_for_coo()
274
+ #json.dump(([float(x) for x in a], ([int(x) for x in b], [int(x) for x in c])), open("fisher.json", "w"))
275
+ if specs is not None:
276
+ self.ll.spec_correction(specs)
File without changes
@@ -0,0 +1,182 @@
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, hydrogen, dist_max_external/dist_min_external
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["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 r["rest_type"] == "stac":
78
+ atoms[i].append(atom)
79
+ else:
80
+ atoms.append(atom)
81
+ if skip or not atoms:
82
+ continue
83
+ if r["rest_type"] in ("spec", "harm"):
84
+ if r["restr"]["rectype"] == "auto":
85
+ assert r["rest_type"] == "spec"
86
+ atoms = [cra.atom for cra in st[0].all()]
87
+ for atom in atoms:
88
+ ex = extypes[r["rest_type"]](atom)
89
+ if r["rest_type"] == "spec":
90
+ # TODO check if it is on special position. using r["restr"]["toler"]
91
+ ex.sigma_t = r["restr"]["sigma_t"]
92
+ ex.sigma_u =r["restr"]["sigma_u"]
93
+ ex.u_val_incl = r["restr"]["u_val_incl"]
94
+ # ex.trans_t =
95
+ # ex.mat_u =
96
+ else:
97
+ ex.sigma = r["restr"]["sigma_t"]
98
+ exlists[r["rest_type"]].append(ex)
99
+ continue
100
+ elif r["rest_type"] == "plan":
101
+ ex = extypes[r["rest_type"]](atoms)
102
+ else:
103
+ ex = extypes[r["rest_type"]](*atoms)
104
+ if r["rest_type"] in ("dist", "angl", "chir", "tors"):
105
+ value = r["restr"]["value"]
106
+ sigma = r["restr"]["sigma_value"] / defs["scale_sigma_{}".format(r["rest_type"])]
107
+ if r["rest_type"] == "chir":
108
+ ex.value = value
109
+ ex.sigma = sigma
110
+ else:
111
+ if r["rest_type"] == "dist":
112
+ sigma = min(max(sigma, defs["sigma_min_loc"]), defs["sigma_max_loc"])
113
+ vals = (value, sigma, value, sigma) # nucleus
114
+ elif r["rest_type"] == "tors":
115
+ vals = (value, sigma, 1) # period. # Refmac does not seem to read it from instruction
116
+ else:
117
+ vals = (value, sigma)
118
+ ex.values.append(extypes[r["rest_type"]].Value(*vals))
119
+
120
+ if r["rest_type"] == "dist":
121
+ if not (defs["dist_min_external"] < r["restr"]["value"] < defs["dist_max_external"]):
122
+ continue
123
+ ex.alpha = r["restr"].get("alpha_in", defs["alpha_default"])
124
+ ex.type = r["restr"].get("itype_in", defs["type_default"])
125
+ symm1 = any([spec.get("symm") for spec in r["restr"]["specs"]]) # is it the intention?
126
+ if r["restr"].get("symm_in", defs["symall_block"]) or symm1:
127
+ asu = gemmi.Asu.Different if defs["exclude_self_block"] else gemmi.Asu.Any
128
+ ex.set_image(st.cell, asu)
129
+ #print("dist=", ex.alpha, ex.type, ex.values[-1].value, ex.values[-1].sigma, ex.sym_idx, ex.pbc_shift, ex.atoms)
130
+ elif r["rest_type"] == "angl":
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])
137
+ #print("angl=", ex.values[-1].value, ex.values[-1].sigma, ex.atoms)
138
+ elif r["rest_type"] == "tors":
139
+ pass
140
+ #print("tors=", ex.values[-1].value, ex.values[-1].sigma, ex.atoms)
141
+ elif r["rest_type"] == "chir":
142
+ #print("chir=", ex.value, ex.sigma, ex.atoms)
143
+ ex.sign = gemmi.ChiralityType.Positive if ex.value > 0 else gemmi.ChiralityType.Negative
144
+ ex.value = abs(ex.value)
145
+ elif r["rest_type"] == "plan":
146
+ ex.sigma = r["restr"]["sigma_value"] / defs["scale_sigma_{}".format(r["rest_type"])]
147
+ #print("plan=", ex.sigma, ex.atoms)
148
+ elif r["rest_type"] == "inte":
149
+ dmin, dmax = r["restr"].get("dmin"), r["restr"].get("dmax")
150
+ smin, smax = r["restr"].get("smin"), r["restr"].get("smax")
151
+ if (smin,smax).count(None) == 2:
152
+ smin = smax = 0.05
153
+ else:
154
+ if smin is None: smin = smax
155
+ if smax is None: smax = smin
156
+ smin /= defs["scale_sigma_inte"]
157
+ smax /= defs["scale_sigma_inte"]
158
+ if (dmin,dmax).count(None) == 1:
159
+ if dmin is None: dmin = dmax
160
+ if dmax is None: dmax = dmin
161
+ ex.dmin = dmin
162
+ ex.dmax = dmax
163
+ ex.smin = smin
164
+ ex.smax = smax
165
+ #print("inte=", ex.dmin, ex.dmax, ex.smin, ex.smax, ex.atoms)
166
+ elif r["rest_type"] == "stac":
167
+ ex.dist = r["restr"]["dist_id"]
168
+ ex.sd_dist = r["restr"]["dist_sd"]
169
+ ex.angle = r["restr"].get("angle_id", 0.)
170
+ ex.sd_angle = r["restr"]["angle_sd"]
171
+ #print("stac=", ex.dist, ex.sd_dist, ex.angle, ex.sd_angle, ex.planes)
172
+
173
+ exlists[r["rest_type"]].append(ex)
174
+
175
+ logger.writeln("External restraints from Refmac instructions")
176
+ labs = dict(dist="distances", angl="angles", tors="torsions",
177
+ chir="chirals", plan="planes", inte="intervals",
178
+ stac="stackings", harm="harmonics", spec="special positions")
179
+ for lab in labs:
180
+ logger.writeln(" Number of {:18s} : {}".format(labs[lab], len(exlists[lab]) - num_org[lab]))
181
+ logger.writeln("")
182
+ # read_external_restraints()