servalcat 0.4.88__cp38-cp38-macosx_11_0_arm64.whl → 0.4.100__cp38-cp38-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-38-darwin.so +0 -0
- servalcat/refine/refine.py +125 -42
- servalcat/refine/refine_geom.py +24 -11
- servalcat/refine/refine_spa.py +55 -31
- servalcat/refine/refine_xtal.py +31 -22
- servalcat/refine/spa.py +12 -4
- servalcat/refine/xtal.py +15 -12
- servalcat/refmac/refmac_wrapper.py +3 -11
- servalcat/spa/fofc.py +9 -3
- servalcat/spa/fsc.py +8 -10
- servalcat/spa/run_refmac.py +16 -11
- servalcat/spa/translate.py +2 -2
- servalcat/utils/commands.py +154 -4
- servalcat/utils/fileio.py +15 -8
- servalcat/utils/hkl.py +63 -26
- servalcat/utils/logger.py +25 -1
- servalcat/utils/maps.py +2 -2
- servalcat/utils/model.py +22 -15
- servalcat/utils/refmac.py +1 -1
- servalcat/utils/restraints.py +27 -28
- servalcat/utils/symmetry.py +5 -5
- servalcat/xtal/french_wilson.py +7 -5
- servalcat/xtal/sigmaa.py +69 -45
- servalcat/xtal/twin.py +73 -44
- {servalcat-0.4.88.dist-info → servalcat-0.4.100.dist-info}/METADATA +4 -4
- servalcat-0.4.100.dist-info/RECORD +45 -0
- {servalcat-0.4.88.dist-info → servalcat-0.4.100.dist-info}/WHEEL +1 -1
- servalcat-0.4.88.dist-info/RECORD +0 -45
- {servalcat-0.4.88.dist-info → servalcat-0.4.100.dist-info}/entry_points.txt +0 -0
- {servalcat-0.4.88.dist-info → servalcat-0.4.100.dist-info}/licenses/LICENSE +0 -0
servalcat/__init__.py
CHANGED
|
Binary file
|
servalcat/refine/refine.py
CHANGED
|
@@ -28,7 +28,7 @@ b_to_u = utils.model.b_to_u
|
|
|
28
28
|
#atexit.register(profile.print_stats)
|
|
29
29
|
|
|
30
30
|
class Geom:
|
|
31
|
-
def __init__(self, st, topo, monlib, adpr_w=1, shake_rms=0,
|
|
31
|
+
def __init__(self, st, topo, monlib, adpr_w=1, occr_w=1, shake_rms=0,
|
|
32
32
|
params=None, unrestrained=False, use_nucleus=False,
|
|
33
33
|
ncslist=None, atom_pos=None):
|
|
34
34
|
self.st = st
|
|
@@ -53,7 +53,7 @@ class Geom:
|
|
|
53
53
|
n_sym = len(images) + 1
|
|
54
54
|
self.geom.specials.append(ext.Geometry.Special(atom, matp, mata, n_sym))
|
|
55
55
|
self.adpr_w = adpr_w
|
|
56
|
-
self.occr_w =
|
|
56
|
+
self.occr_w = occr_w
|
|
57
57
|
self.unrestrained = unrestrained
|
|
58
58
|
if shake_rms > 0:
|
|
59
59
|
numpy.random.seed(0)
|
|
@@ -225,6 +225,26 @@ def write_stats_json_safe(stats, json_out):
|
|
|
225
225
|
logger.writeln(f"Refinement statistics saved: {json_out}")
|
|
226
226
|
# write_stats_json_safe()
|
|
227
227
|
|
|
228
|
+
def print_h_options(h_change, h_present, refine_h, hout, geom_only):
|
|
229
|
+
if not h_present:
|
|
230
|
+
h_change = gemmi.HydrogenChange.Remove
|
|
231
|
+
logger.writeln("Hydrogen related options")
|
|
232
|
+
logger.write(" use in refinement{}: hydrogen atoms ".format("" if geom_only else "/map calculation"))
|
|
233
|
+
logger.writeln({gemmi.HydrogenChange.ReAddButWater: "have been (re)generated",
|
|
234
|
+
gemmi.HydrogenChange.ReAdd: "(including water) have been (re)generated",
|
|
235
|
+
gemmi.HydrogenChange.ReAddKnown: "(except for rotatable) have been (re) generated",
|
|
236
|
+
gemmi.HydrogenChange.NoChange: "from the input model have been retained",
|
|
237
|
+
gemmi.HydrogenChange.Remove: "have either been removed or were not present"}[h_change])
|
|
238
|
+
if h_present:
|
|
239
|
+
logger.write(" target: hydrogen atoms will be ")
|
|
240
|
+
if geom_only or not refine_h:
|
|
241
|
+
logger.writeln("just optimized according to geometric restraints")
|
|
242
|
+
else:
|
|
243
|
+
logger.writeln("refined against experimental data")
|
|
244
|
+
logger.writeln(" in output model: " + ("written" if hout and h_present else "not written"))
|
|
245
|
+
logger.writeln("")
|
|
246
|
+
# print_hydrogen_options()
|
|
247
|
+
|
|
228
248
|
class GroupOccupancy:
|
|
229
249
|
# TODO max may not be one. should check multiplicity
|
|
230
250
|
def __init__(self, st, params):
|
|
@@ -293,6 +313,7 @@ class GroupOccupancy:
|
|
|
293
313
|
vals = []
|
|
294
314
|
for _, atoms in self.groups:
|
|
295
315
|
occ = numpy.mean([a.occ for a in atoms])
|
|
316
|
+
occ = min(1, max(1e-3, occ))
|
|
296
317
|
vals.append(occ)
|
|
297
318
|
for is_comp, idxes in self.consts:
|
|
298
319
|
sum_occ = sum(vals[i] for i in idxes)
|
|
@@ -311,6 +332,7 @@ class GroupOccupancy:
|
|
|
311
332
|
for p, (_, atoms) in zip(x, self.groups):
|
|
312
333
|
for a in atoms:
|
|
313
334
|
a.occ = p
|
|
335
|
+
#a.occ = max(1, min(1e-3, p))
|
|
314
336
|
|
|
315
337
|
def target(self, x, ll, ls, u):
|
|
316
338
|
self.set_x(x)
|
|
@@ -425,7 +447,7 @@ class Refine:
|
|
|
425
447
|
self.geom.set_h_parents()
|
|
426
448
|
if params and params.get("write_trajectory"):
|
|
427
449
|
self.st_traj = self.st.clone()
|
|
428
|
-
self.st_traj[-1].
|
|
450
|
+
self.st_traj[-1].num = 0
|
|
429
451
|
assert self.geom.group_occ.groups or self.n_params() > 0
|
|
430
452
|
# __init__()
|
|
431
453
|
|
|
@@ -442,6 +464,9 @@ class Refine:
|
|
|
442
464
|
logger.writeln(" sigmas: {}".format(" ".join("{:.2f}".format(x) for x in g.adpr_kl_sigs)))
|
|
443
465
|
else:
|
|
444
466
|
raise LookupError("unknown adpr_mode")
|
|
467
|
+
if self.refine_occ:
|
|
468
|
+
logger.writeln(" Occupancy restraints")
|
|
469
|
+
logger.writeln(" weight: {}".format(self.geom.occr_w))
|
|
445
470
|
|
|
446
471
|
def scale_shifts(self, dx, scale):
|
|
447
472
|
n_atoms = self.geom.n_refine_atoms
|
|
@@ -525,7 +550,7 @@ class Refine:
|
|
|
525
550
|
elif self.adp_mode == 2:
|
|
526
551
|
a = x[offset_b + 6 * j: offset_b + 6 * (j+1)]
|
|
527
552
|
a = gemmi.SMat33d(*a)
|
|
528
|
-
M =
|
|
553
|
+
M = a.as_mat33().array
|
|
529
554
|
v, Q = numpy.linalg.eigh(M) # eig() may return complex due to numerical precision?
|
|
530
555
|
v = numpy.maximum(v, 0.5) # avoid NPD with minimum B = 0.5
|
|
531
556
|
M2 = Q.dot(numpy.diag(v)).dot(Q.T)
|
|
@@ -736,7 +761,7 @@ class Refine:
|
|
|
736
761
|
weight /= 1.1
|
|
737
762
|
if self.st_traj is not None:
|
|
738
763
|
self.st_traj.add_model(self.st[0])
|
|
739
|
-
self.st_traj[-1].
|
|
764
|
+
self.st_traj[-1].num = len(self.st_traj)
|
|
740
765
|
if stats_json_out:
|
|
741
766
|
write_stats_json_safe(stats, stats_json_out)
|
|
742
767
|
|
|
@@ -781,43 +806,101 @@ class Refine:
|
|
|
781
806
|
lstr = utils.make_loggraph_str(df, "stats vs cycle", forplot,
|
|
782
807
|
float_format="{:.4f}".format)
|
|
783
808
|
logger.writeln(lstr)
|
|
784
|
-
self.update_meta(stats[-1])
|
|
785
809
|
return stats
|
|
786
810
|
|
|
787
|
-
def update_meta(self, stats):
|
|
788
|
-
# TODO write stats. probably geom.reporting.get_summary_table should return with _refine_ls_restr.type names
|
|
789
|
-
# should remove st.mod_residues?
|
|
790
|
-
self.st.helices.clear()
|
|
791
|
-
self.st.sheets.clear()
|
|
792
|
-
raw_remarks = [f'REMARK 3',
|
|
793
|
-
f'REMARK 3 REFINEMENT.',
|
|
794
|
-
f'REMARK 3 PROGRAM : SERVALCAT {servalcat.__version__}',
|
|
795
|
-
f'REMARK 3 AUTHORS : YAMASHITA,MURSHUDOV',
|
|
796
|
-
f'REMARK 3',
|
|
797
|
-
]
|
|
798
|
-
si = gemmi.SoftwareItem()
|
|
799
|
-
si.classification = gemmi.SoftwareItem.Classification.Refinement
|
|
800
|
-
si.name = "Servalcat"
|
|
801
|
-
si.version = servalcat.__version__
|
|
802
|
-
si.date = servalcat.__date__
|
|
803
|
-
self.st.meta.software = [si]
|
|
804
|
-
|
|
805
|
-
ri = gemmi.RefinementInfo()
|
|
806
|
-
if "geom" in stats:
|
|
807
|
-
restr_stats = []
|
|
808
|
-
raw_remarks.append("REMARK 3 RMS DEVIATIONS FROM IDEAL VALUES COUNT RMS WEIGHT")
|
|
809
|
-
for k, n, l, pl in (("r.m.s.d.", "Bond distances, non H", "s_bond_nonh_d", "BOND LENGTHS REFINED ATOMS (A)"),
|
|
810
|
-
("r.m.s.d.", "Bond angles, non H", "s_angle_nonh_d", "BOND ANGLES REFINED ATOMS (DEGREES)")):
|
|
811
|
-
if k in stats["geom"]["summary"] and n in stats["geom"]["summary"][k]:
|
|
812
|
-
rr = gemmi.RefinementInfo.Restr(l)
|
|
813
|
-
rr.dev_ideal = stats["geom"]["summary"][k].get(n)
|
|
814
|
-
rr.count = stats["geom"]["summary"]["N restraints"].get(n)
|
|
815
|
-
rr.weight = stats["geom"]["summary"]["Mn(sigma)"].get(n)
|
|
816
|
-
restr_stats.append(rr)
|
|
817
|
-
raw_remarks.append(f"REMARK 3 {pl}:{rr.count:6d} ;{rr.dev_ideal:6.3f} ;{rr.weight:6.3f}")
|
|
818
|
-
ri.restr_stats = restr_stats
|
|
819
|
-
raw_remarks.append("REMARK 3")
|
|
820
|
-
self.st.meta.refinement = [ri]
|
|
821
|
-
self.st.raw_remarks = raw_remarks
|
|
822
|
-
|
|
823
811
|
# class Refine
|
|
812
|
+
|
|
813
|
+
def update_meta(st, stats, ll=None):
|
|
814
|
+
# TODO write stats. probably geom.reporting.get_summary_table should return with _refine_ls_restr.type names
|
|
815
|
+
# should remove st.mod_residues?
|
|
816
|
+
st.helices.clear()
|
|
817
|
+
st.sheets.clear()
|
|
818
|
+
raw_remarks = [f'REMARK 3',
|
|
819
|
+
f'REMARK 3 REFINEMENT.',
|
|
820
|
+
f'REMARK 3 PROGRAM : SERVALCAT {servalcat.__version__}',
|
|
821
|
+
f'REMARK 3 AUTHORS : YAMASHITA,MURSHUDOV',
|
|
822
|
+
f'REMARK 3',
|
|
823
|
+
]
|
|
824
|
+
si = gemmi.SoftwareItem()
|
|
825
|
+
si.classification = gemmi.SoftwareItem.Classification.Refinement
|
|
826
|
+
si.name = "Servalcat"
|
|
827
|
+
si.version = servalcat.__version__
|
|
828
|
+
si.date = servalcat.__date__
|
|
829
|
+
st.meta.software = [si]
|
|
830
|
+
|
|
831
|
+
ri = gemmi.RefinementInfo()
|
|
832
|
+
if "geom" in stats:
|
|
833
|
+
restr_stats = []
|
|
834
|
+
raw_remarks.append("REMARK 3 RMS DEVIATIONS FROM IDEAL VALUES COUNT RMS WEIGHT")
|
|
835
|
+
for k, n, l, pl in (("r.m.s.d.", "Bond distances, non H", "s_bond_nonh_d", "BOND LENGTHS REFINED ATOMS (A)"),
|
|
836
|
+
("r.m.s.d.", "Bond angles, non H", "s_angle_nonh_deg", "BOND ANGLES REFINED ATOMS (DEGREES)"),
|
|
837
|
+
("r.m.s.d.", "Torsion angles, period 1", "s_dihedral_angle_1_deg", "TORSION ANGLES, PERIOD 1 (DEGREES)"),
|
|
838
|
+
("r.m.s.d.", "Torsion angles, period 2", "s_dihedral_angle_2_deg", "TORSION ANGLES, PERIOD 2 (DEGREES)"),
|
|
839
|
+
("r.m.s.d.", "Torsion angles, period 3", "s_dihedral_angle_3_deg", "TORSION ANGLES, PERIOD 3 (DEGREES)"),
|
|
840
|
+
("r.m.s.d.", "Torsion angles, period 6", "s_dihedral_angle_6_deg", "TORSION ANGLES, PERIOD 6 (DEGREES)"),
|
|
841
|
+
("r.m.s.d.", "Chiral centres", "s_chiral_restr", "CHIRAL-CENTER RESTRAINTS (A**3)"),
|
|
842
|
+
("r.m.s.d.", "Planar groups", "s_planes", "GENERAL PLANES REFINED ATOMS (A)"),
|
|
843
|
+
("r.m.s.d.", "VDW nonbonded", "s_nbd", ""),
|
|
844
|
+
("r.m.s.d.", "VDW torsion", "s_nbtor", ""),
|
|
845
|
+
("r.m.s.d.", "VDW hbond", "s_hbond_nbd", ""),
|
|
846
|
+
("r.m.s.d.", "VDW metal", "s_metal_ion", ""),
|
|
847
|
+
("r.m.s.d.", "VDW dummy", "s_dummy_nbd", ""),
|
|
848
|
+
("r.m.s.d.", "VDW nonbonded, symmetry", "s_symmetry_nbd", ""),
|
|
849
|
+
("r.m.s.d.", "VDW torsion, symmetry", "s_symmetry_nbtor", ""),
|
|
850
|
+
("r.m.s.d.", "VDW hbond, symmetry", "s_symmetry_hbond_nbd", ""),
|
|
851
|
+
("r.m.s.d.", "VDW metal, symmetry", "s_symmetry_metal_ion", ""),
|
|
852
|
+
("r.m.s.d.", "VDW dummy, symmetry", "s_symmetry_dummy_nbd", "")):
|
|
853
|
+
if k in stats["geom"]["summary"] and n in stats["geom"]["summary"][k]:
|
|
854
|
+
rr = gemmi.RefinementInfo.Restr(l)
|
|
855
|
+
rr.dev_ideal = round(stats["geom"]["summary"][k].get(n), 4)
|
|
856
|
+
rr.count = stats["geom"]["summary"]["N restraints"].get(n)
|
|
857
|
+
rr.weight = round(stats["geom"]["summary"]["Mn(sigma)"].get(n), 4)
|
|
858
|
+
restr_stats.append(rr)
|
|
859
|
+
if pl:
|
|
860
|
+
raw_remarks.append(f"REMARK 3 {pl}:{rr.count:6d} ;{rr.dev_ideal:6.3f} ;{rr.weight:6.3f}")
|
|
861
|
+
ri.restr_stats = restr_stats
|
|
862
|
+
raw_remarks.append("REMARK 3")
|
|
863
|
+
if ll is not None:
|
|
864
|
+
ri.id = ll.refine_id()
|
|
865
|
+
ri.mean_b = round(numpy.mean([cra.atom.b_iso for cra in st[0].all()]), 2)
|
|
866
|
+
if ll.b_aniso is not None:
|
|
867
|
+
ri.aniso_b = ll.b_aniso
|
|
868
|
+
for k, kd, nd in (("Rwork", "r_work", 4), ("Rfree", "r_free", 4), ("R", "r_all", 4),
|
|
869
|
+
("FSCaverage", "fsc_work", 4),
|
|
870
|
+
("FSCaverage_half1", "fsc_work", 4), ("FSCaverage_half2", "fsc_free", 4)):
|
|
871
|
+
if k in stats["data"]["summary"]:
|
|
872
|
+
setattr(ri, kd, round(stats["data"]["summary"][k], nd))
|
|
873
|
+
bins = []
|
|
874
|
+
n_all = 0
|
|
875
|
+
for b in stats["data"]["binned"]:
|
|
876
|
+
bri = gemmi.BasicRefinementInfo()
|
|
877
|
+
bri.resolution_high = round(b["d_min"], 3)
|
|
878
|
+
bri.resolution_low = round(b["d_max"], 3)
|
|
879
|
+
for k, kd, nd in (("Rwork", "r_work", 4), ("Rfree", "r_free", 4),
|
|
880
|
+
("R1work", "r_work", 4), ("R1free", "r_free", 4),
|
|
881
|
+
("R", "r_all", 4), ("R1", "r_all", 4),
|
|
882
|
+
("CCI", "cc_intensity_work", 4), ("CCF", "cc_fo_fc_work", 4),
|
|
883
|
+
("CCIwork", "cc_intensity_work", 4), ("CCIfree", "cc_intensity_free", 4),
|
|
884
|
+
("CCFwork", "cc_fo_fc_work", 4), ("CCFfree", "cc_fo_fc_free", 4),
|
|
885
|
+
("fsc_FC_full", "fsc_work", 4), ("fsc_model", "fsc_work", 4),
|
|
886
|
+
("fsc_model_half1", "fsc_work", 4), ("fsc_model_half2", "fsc_free", 4),
|
|
887
|
+
("n_work", "work_set_count", 0), ("n_free", "rfree_set_count", 0),
|
|
888
|
+
("n_obs", "reflection_count", 0), ("ncoeffs", "reflection_count", 0)):
|
|
889
|
+
if k in b: setattr(bri, kd, round(b[k], nd))
|
|
890
|
+
if "n_all" in b and "n_obs" in b:
|
|
891
|
+
bri.completeness = round(b["n_obs"] / b["n_all"] * 100, 2)
|
|
892
|
+
n_all += b["n_all"]
|
|
893
|
+
bins.append(bri)
|
|
894
|
+
ri.rfree_set_count = max(-1, sum(b.rfree_set_count for b in bins))
|
|
895
|
+
ri.work_set_count = max(-1, sum(b.work_set_count for b in bins))
|
|
896
|
+
ri.reflection_count = max(-1, sum(b.reflection_count for b in bins))
|
|
897
|
+
ri.resolution_high = round(min(b.resolution_high for b in bins), 3)
|
|
898
|
+
ri.resolution_low = round(max(b.resolution_low for b in bins), 3)
|
|
899
|
+
if ri.reflection_count > 0 and n_all > 0:
|
|
900
|
+
ri.completeness = round(ri.reflection_count / n_all * 100, 2)
|
|
901
|
+
ri.bins = bins
|
|
902
|
+
if ri.rfree_set_count > 0:
|
|
903
|
+
ri.cross_validation_method = "THROUGHOUT"
|
|
904
|
+
st.meta.refinement = [ri]
|
|
905
|
+
st.raw_remarks = raw_remarks
|
|
906
|
+
# update_meta()
|
servalcat/refine/refine_geom.py
CHANGED
|
@@ -14,7 +14,7 @@ import json
|
|
|
14
14
|
import servalcat # for version
|
|
15
15
|
from servalcat.utils import logger
|
|
16
16
|
from servalcat import utils
|
|
17
|
-
from servalcat.refine.refine import Geom, Refine, convert_stats_to_dicts
|
|
17
|
+
from servalcat.refine.refine import Geom, Refine, convert_stats_to_dicts, update_meta, print_h_options
|
|
18
18
|
from servalcat.refmac import refmac_keywords
|
|
19
19
|
|
|
20
20
|
def add_arguments(parser):
|
|
@@ -93,9 +93,14 @@ def refine_and_update_dictionary(cif_in, monomer_dir, output_prefix, randomize=0
|
|
|
93
93
|
if len(st) > 0: break
|
|
94
94
|
else:
|
|
95
95
|
raise SystemExit("No model in the cif file")
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
96
|
+
for i in range(len(st)-1):
|
|
97
|
+
del st[1]
|
|
98
|
+
try:
|
|
99
|
+
monlib = utils.restraints.load_monomer_library(st, monomer_dir=monomer_dir, # monlib is needed for ener_lib
|
|
100
|
+
cif_files=[cif_in],
|
|
101
|
+
stop_for_unknowns=True)
|
|
102
|
+
except RuntimeError as e:
|
|
103
|
+
raise SystemExit("Error: {}".format(e))
|
|
99
104
|
all_stats = []
|
|
100
105
|
for i_macro in 0, 1:
|
|
101
106
|
try:
|
|
@@ -121,16 +126,19 @@ def refine_and_update_dictionary(cif_in, monomer_dir, output_prefix, randomize=0
|
|
|
121
126
|
for row in block.find("_chem_comp_atom.", ["atom_id", "?x", "?y", "?z",
|
|
122
127
|
"?pdbx_model_Cartn_x_ideal",
|
|
123
128
|
"?pdbx_model_Cartn_y_ideal",
|
|
124
|
-
"?pdbx_model_Cartn_z_ideal"
|
|
129
|
+
"?pdbx_model_Cartn_z_ideal",
|
|
130
|
+
"?model_Cartn_x", "?model_Cartn_y", "?model_Cartn_z"]):
|
|
125
131
|
p = pos[row.str(0)]
|
|
126
132
|
for i in range(3):
|
|
127
133
|
if row.has(i+1):
|
|
128
134
|
row[i+1] = "{:.3f}".format(p[i])
|
|
129
135
|
if row.has(i+4):
|
|
130
136
|
row[i+4] = "{:.3f}".format(p[i])
|
|
137
|
+
if row.has(i+7):
|
|
138
|
+
row[i+7] = "{:.3f}".format(p[i])
|
|
131
139
|
# add description
|
|
132
140
|
add_program_info_to_dictionary(block, st[0][0][0].name)
|
|
133
|
-
doc.write_file(output_prefix + "_updated.cif",
|
|
141
|
+
doc.write_file(output_prefix + "_updated.cif", options=gemmi.cif.Style.Aligned)
|
|
134
142
|
logger.writeln("Updated dictionary saved: {}".format(output_prefix + "_updated.cif"))
|
|
135
143
|
with open(output_prefix + "_stats.json", "w") as ofs:
|
|
136
144
|
json.dump([convert_stats_to_dicts(x) for x in all_stats],
|
|
@@ -147,11 +155,13 @@ def refine_geom(model_in, monomer_dir, cif_files, h_change, ncycle, output_prefi
|
|
|
147
155
|
logger.writeln("Take NCS constraints into account.")
|
|
148
156
|
st2.expand_ncs(gemmi.HowToNameCopiedChain.Dup, merge_dist=0)
|
|
149
157
|
utils.fileio.write_model(st2, file_name="input_expanded.pdb")
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
158
|
+
try:
|
|
159
|
+
monlib = utils.restraints.load_monomer_library(st, monomer_dir=monomer_dir,
|
|
160
|
+
cif_files=cif_files,
|
|
161
|
+
stop_for_unknowns=True,
|
|
162
|
+
params=params)
|
|
163
|
+
except RuntimeError as e:
|
|
164
|
+
raise SystemExit("Error: {}".format(e))
|
|
155
165
|
utils.restraints.find_and_fix_links(st, monlib, find_metal_links=find_links,
|
|
156
166
|
add_found=find_links) # should remove unknown id here?
|
|
157
167
|
try:
|
|
@@ -161,6 +171,8 @@ def refine_geom(model_in, monomer_dir, cif_files, h_change, ncycle, output_prefi
|
|
|
161
171
|
except RuntimeError as e:
|
|
162
172
|
raise SystemExit("Error: {}".format(e))
|
|
163
173
|
|
|
174
|
+
print_h_options(h_change, st[0].has_hydrogen(), refine_h=True, hout=True, geom_only=True)
|
|
175
|
+
|
|
164
176
|
if use_ncsr:
|
|
165
177
|
ncslist = utils.restraints.prepare_ncs_restraints(st)
|
|
166
178
|
else:
|
|
@@ -169,6 +181,7 @@ def refine_geom(model_in, monomer_dir, cif_files, h_change, ncycle, output_prefi
|
|
|
169
181
|
refiner = Refine(st, geom, params=params)
|
|
170
182
|
stats = refiner.run_cycles(ncycle,
|
|
171
183
|
stats_json_out=output_prefix + "_stats.json")
|
|
184
|
+
update_meta(st, stats[-1])
|
|
172
185
|
refiner.st.name = output_prefix
|
|
173
186
|
utils.fileio.write_model(refiner.st, output_prefix, pdb=True, cif=True)
|
|
174
187
|
if params["write_trajectory"]:
|
servalcat/refine/refine_spa.py
CHANGED
|
@@ -14,12 +14,12 @@ from servalcat import utils
|
|
|
14
14
|
from servalcat.spa.run_refmac import check_args, process_input, calc_fsc, calc_fofc
|
|
15
15
|
from servalcat.spa import fofc
|
|
16
16
|
from servalcat.refine import spa
|
|
17
|
-
from servalcat.refine.refine import Geom, Refine
|
|
17
|
+
from servalcat.refine.refine import Geom, Refine, update_meta, print_h_options
|
|
18
18
|
from servalcat.refmac import refmac_keywords
|
|
19
19
|
b_to_u = utils.model.b_to_u
|
|
20
20
|
|
|
21
21
|
def add_arguments(parser):
|
|
22
|
-
parser.description = "
|
|
22
|
+
parser.description = "program to refine cryo-EM SPA structures"
|
|
23
23
|
group = parser.add_mutually_exclusive_group(required=True)
|
|
24
24
|
group.add_argument("--halfmaps", nargs=2, help="Input half map files")
|
|
25
25
|
group.add_argument("--map", help="Use this only if you really do not have half maps.")
|
|
@@ -68,7 +68,7 @@ def add_arguments(parser):
|
|
|
68
68
|
help="Jelly body only (experimental, may not be useful)")
|
|
69
69
|
utils.symmetry.add_symmetry_args(parser) # add --pg etc
|
|
70
70
|
parser.add_argument('--contacting_only', action="store_true", help="Filter out non-contacting strict NCS copies")
|
|
71
|
-
parser.add_argument('--ignore_symmetry',
|
|
71
|
+
parser.add_argument('--ignore_symmetry', action='store_true',
|
|
72
72
|
help='Ignore symmetry information (MTRIX/_struct_ncs_oper) in the model file')
|
|
73
73
|
parser.add_argument('--find_links', action='store_true',
|
|
74
74
|
help='Automatically add links')
|
|
@@ -94,6 +94,8 @@ def add_arguments(parser):
|
|
|
94
94
|
help='Bond rmsz range for weight adjustment (default: %(default)s)')
|
|
95
95
|
parser.add_argument('--adpr_weight', type=float, default=1.,
|
|
96
96
|
help="ADP restraint weight (default: %(default)f)")
|
|
97
|
+
parser.add_argument('--occr_weight', type=float, default=1.,
|
|
98
|
+
help="Occupancy restraint weight (default: %(default)f)")
|
|
97
99
|
parser.add_argument('--ncsr', action='store_true',
|
|
98
100
|
help='Use local NCS restraints')
|
|
99
101
|
parser.add_argument('--bfactor', type=float,
|
|
@@ -108,8 +110,9 @@ def add_arguments(parser):
|
|
|
108
110
|
parser.add_argument('--adp_restraint_exp_fac', type=float)
|
|
109
111
|
parser.add_argument('--adp_restraint_no_long_range', action='store_true')
|
|
110
112
|
parser.add_argument('--adp_restraint_mode', choices=["diff", "kldiv"], default="diff")
|
|
113
|
+
parser.add_argument('--unrestrained', action='store_true', help="No positional restraints")
|
|
111
114
|
parser.add_argument('--refine_h', action="store_true", help="Refine hydrogen against data (default: only restraints apply)")
|
|
112
|
-
parser.add_argument("--source", choices=["electron", "xray", "neutron"], default="electron")
|
|
115
|
+
parser.add_argument("-s", "--source", choices=["electron", "xray", "neutron"], default="electron")
|
|
113
116
|
parser.add_argument('-o','--output_prefix', default="refined")
|
|
114
117
|
parser.add_argument('--cross_validation', action='store_true',
|
|
115
118
|
help='Run cross validation. Only "throughout" mode is available (no "shake" mode)')
|
|
@@ -142,12 +145,23 @@ def main(args):
|
|
|
142
145
|
params["write_trajectory"] = args.write_trajectory
|
|
143
146
|
|
|
144
147
|
st = utils.fileio.read_structure(args.model)
|
|
145
|
-
|
|
146
|
-
monlib =
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
if args.unrestrained:
|
|
149
|
+
monlib = gemmi.MonLib()
|
|
150
|
+
topo = None
|
|
151
|
+
if args.hydrogen == "all":
|
|
152
|
+
logger.writeln("\nWARNING: in unrestrained refinement hydrogen atoms are not generated.\n")
|
|
153
|
+
args.hydrogen = "yes"
|
|
154
|
+
elif args.hydrogen == "no":
|
|
155
|
+
st.remove_hydrogens()
|
|
156
|
+
for i, cra in enumerate(st[0].all()):
|
|
157
|
+
cra.atom.serial = i + 1
|
|
158
|
+
else:
|
|
159
|
+
try:
|
|
160
|
+
monlib = utils.restraints.load_monomer_library(st, monomer_dir=args.monlib, cif_files=args.ligand,
|
|
161
|
+
stop_for_unknowns=not args.newligand_continue,
|
|
162
|
+
params=params)
|
|
163
|
+
except RuntimeError as e:
|
|
164
|
+
raise SystemExit("Error: {}".format(e))
|
|
151
165
|
if not args.keep_entities:
|
|
152
166
|
utils.model.setup_entities(st, clear=True, force_subchain_names=True, overwrite_entity_type=True)
|
|
153
167
|
if not args.keep_charges:
|
|
@@ -186,6 +200,8 @@ def main(args):
|
|
|
186
200
|
except RuntimeError as e:
|
|
187
201
|
raise SystemExit("Error: {}".format(e))
|
|
188
202
|
|
|
203
|
+
print_h_options(h_change, st[0].has_hydrogen(), args.refine_h, args.hout, geom_only=False)
|
|
204
|
+
|
|
189
205
|
# initialize ADP
|
|
190
206
|
utils.model.reset_adp(st[0], args.bfactor, args.adp)
|
|
191
207
|
|
|
@@ -214,8 +230,8 @@ def main(args):
|
|
|
214
230
|
ncslist = utils.restraints.prepare_ncs_restraints(st)
|
|
215
231
|
else:
|
|
216
232
|
ncslist = False
|
|
217
|
-
geom = Geom(st, topo, monlib, shake_rms=args.randomize, adpr_w=args.adpr_weight,
|
|
218
|
-
params=params, unrestrained=args.jellyonly,
|
|
233
|
+
geom = Geom(st, topo, monlib, shake_rms=args.randomize, adpr_w=args.adpr_weight, occr_w=args.occr_weight,
|
|
234
|
+
params=params, unrestrained=args.unrestrained or args.jellyonly,
|
|
219
235
|
ncslist=ncslist)
|
|
220
236
|
ll = spa.LL_SPA(hkldata, st, monlib,
|
|
221
237
|
lab_obs="F_map1" if args.cross_validation else "FP",
|
|
@@ -224,6 +240,7 @@ def main(args):
|
|
|
224
240
|
refine_xyz=not args.fix_xyz,
|
|
225
241
|
adp_mode=dict(fix=0, iso=1, aniso=2)[args.adp],
|
|
226
242
|
refine_h=args.refine_h,
|
|
243
|
+
unrestrained=args.unrestrained,
|
|
227
244
|
params=params,
|
|
228
245
|
refine_occ=args.refine_all_occ)
|
|
229
246
|
|
|
@@ -247,34 +264,41 @@ def main(args):
|
|
|
247
264
|
refiner.st.cell = maps[0][0].unit_cell
|
|
248
265
|
refiner.st.setup_cell_images()
|
|
249
266
|
|
|
250
|
-
refiner.st.name = args.output_prefix
|
|
251
|
-
utils.fileio.write_model(refiner.st, args.output_prefix, pdb=True, cif=True, hout=args.hout)
|
|
252
267
|
if params["write_trajectory"]:
|
|
253
268
|
utils.fileio.write_model(refiner.st_traj, args.output_prefix + "_traj", cif=True)
|
|
254
|
-
if args.hklin:
|
|
255
|
-
return
|
|
256
269
|
|
|
257
270
|
# Expand sym here
|
|
258
271
|
st_expanded = refiner.st.clone()
|
|
259
272
|
if not all(op.given for op in st.ncs):
|
|
260
273
|
utils.model.expand_ncs(st_expanded)
|
|
261
|
-
utils.fileio.write_model(st_expanded, args.output_prefix+"_expanded", pdb=True, cif=True, hout=args.hout)
|
|
262
274
|
|
|
263
275
|
# Calc FSC
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
276
|
+
if args.hklin: # cannot update a mask
|
|
277
|
+
stats_for_meta = stats[-1]
|
|
278
|
+
else:
|
|
279
|
+
mask = utils.fileio.read_ccp4_map(args.mask)[0] if args.mask else None
|
|
280
|
+
fscavg_text, stats2 = calc_fsc(st_expanded, args.output_prefix, maps,
|
|
281
|
+
args.resolution, mask=mask, mask_radius=args.mask_radius if not args.no_mask else None,
|
|
282
|
+
soft_edge=args.mask_soft_edge,
|
|
283
|
+
b_before_mask=args.b_before_mask,
|
|
284
|
+
no_sharpen_before_mask=args.no_sharpen_before_mask,
|
|
285
|
+
make_hydrogen="yes", # no change needed in the model
|
|
286
|
+
monlib=monlib,
|
|
287
|
+
blur=args.blur,
|
|
288
|
+
d_min_fsc=args.fsc_resolution,
|
|
289
|
+
cross_validation=args.cross_validation,
|
|
290
|
+
cross_validation_method=args.cross_validation_method
|
|
291
|
+
)
|
|
292
|
+
stats_for_meta = {"geom": stats[-1]["geom"], "data": stats2}
|
|
293
|
+
update_meta(refiner.st, stats_for_meta, ll)
|
|
294
|
+
refiner.st.name = args.output_prefix
|
|
295
|
+
utils.fileio.write_model(refiner.st, args.output_prefix, pdb=True, cif=True, hout=args.hout)
|
|
296
|
+
if not all(op.given for op in st.ncs): # to apply updated metadata
|
|
297
|
+
st_expanded = refiner.st.clone()
|
|
298
|
+
utils.model.expand_ncs(st_expanded)
|
|
299
|
+
utils.fileio.write_model(st_expanded, args.output_prefix+"_expanded", pdb=True, cif=True, hout=args.hout)
|
|
300
|
+
if args.hklin:
|
|
301
|
+
return
|
|
278
302
|
# Calc Fo-Fc (and updated) maps
|
|
279
303
|
diffmap_prefix = "{}_diffmap".format(args.output_prefix)
|
|
280
304
|
calc_fofc(refiner.st, st_expanded, maps, monlib, ".mmcif", args, diffmap_prefix=diffmap_prefix)
|
servalcat/refine/refine_xtal.py
CHANGED
|
@@ -16,13 +16,13 @@ from servalcat.utils import logger
|
|
|
16
16
|
from servalcat import utils
|
|
17
17
|
from servalcat.xtal.sigmaa import decide_mtz_labels, process_input, calculate_maps, calculate_maps_int, calculate_maps_twin
|
|
18
18
|
from servalcat.refine.xtal import LL_Xtal
|
|
19
|
-
from servalcat.refine.refine import Geom, Refine
|
|
19
|
+
from servalcat.refine.refine import Geom, Refine, update_meta, print_h_options
|
|
20
20
|
from servalcat.refmac import refmac_keywords
|
|
21
21
|
from servalcat import ext
|
|
22
22
|
b_to_u = utils.model.b_to_u
|
|
23
23
|
|
|
24
24
|
def add_arguments(parser):
|
|
25
|
-
parser.description = "
|
|
25
|
+
parser.description = "program to refine crystallographic structures"
|
|
26
26
|
parser.add_argument("--hklin", required=True)
|
|
27
27
|
parser.add_argument("-d", '--d_min', type=float)
|
|
28
28
|
parser.add_argument('--d_max', type=float)
|
|
@@ -64,10 +64,14 @@ def add_arguments(parser):
|
|
|
64
64
|
help="refinement weight (default: auto)")
|
|
65
65
|
parser.add_argument('--no_weight_adjust', action='store_true',
|
|
66
66
|
help='Do not adjust weight during refinement')
|
|
67
|
+
parser.add_argument('--target_bond_rmsz_range', nargs=2, type=float, default=[0.5, 1.],
|
|
68
|
+
help='Bond rmsz range for weight adjustment (default: %(default)s)')
|
|
67
69
|
parser.add_argument('--ncsr', action='store_true',
|
|
68
70
|
help='Use local NCS restraints')
|
|
69
71
|
parser.add_argument('--adpr_weight', type=float, default=1.,
|
|
70
72
|
help="ADP restraint weight (default: %(default)f)")
|
|
73
|
+
parser.add_argument('--occr_weight', type=float, default=1.,
|
|
74
|
+
help="Occupancy restraint weight (default: %(default)f)")
|
|
71
75
|
parser.add_argument('--bfactor', type=float,
|
|
72
76
|
help="reset all atomic B values to specified value")
|
|
73
77
|
parser.add_argument('--fix_xyz', action="store_true")
|
|
@@ -88,6 +92,8 @@ def add_arguments(parser):
|
|
|
88
92
|
help="Use work reflections in ML parameter estimates")
|
|
89
93
|
parser.add_argument('--keep_charges', action='store_true',
|
|
90
94
|
help="Use scattering factor for charged atoms. Use it with care.")
|
|
95
|
+
parser.add_argument("--keep_entities", action='store_true',
|
|
96
|
+
help="Do not override entities")
|
|
91
97
|
parser.add_argument('--allow_unusual_occupancies', action="store_true", help="Allow negative or more than one occupancies")
|
|
92
98
|
parser.add_argument('-o','--output_prefix')
|
|
93
99
|
parser.add_argument("--write_trajectory", action='store_true',
|
|
@@ -123,19 +129,6 @@ def main(args):
|
|
|
123
129
|
hklin = utils.fileio.read_mmhkl(hklin)
|
|
124
130
|
labin = decide_mtz_labels(hklin)
|
|
125
131
|
|
|
126
|
-
if labin and len(labin) == 3: # with test flags
|
|
127
|
-
use_in_target = "work"
|
|
128
|
-
if args.use_work_in_est:
|
|
129
|
-
use_in_est = "work"
|
|
130
|
-
n_per_bin = 100
|
|
131
|
-
else:
|
|
132
|
-
use_in_est = "test"
|
|
133
|
-
n_per_bin = 50
|
|
134
|
-
else:
|
|
135
|
-
use_in_est = "all"
|
|
136
|
-
use_in_target = "all"
|
|
137
|
-
n_per_bin = 100
|
|
138
|
-
|
|
139
132
|
try:
|
|
140
133
|
hkldata, sts, fc_labs, centric_and_selections, args.free = process_input(hklin=hklin,
|
|
141
134
|
labin=labin,
|
|
@@ -145,24 +138,35 @@ def main(args):
|
|
|
145
138
|
source=args.source,
|
|
146
139
|
d_max=args.d_max,
|
|
147
140
|
d_min=args.d_min,
|
|
148
|
-
|
|
149
|
-
use=use_in_est,
|
|
141
|
+
use="work" if args.use_work_in_est else "test",
|
|
150
142
|
max_bins=30,
|
|
151
143
|
keep_charges=args.keep_charges,
|
|
152
144
|
allow_unusual_occupancies=args.allow_unusual_occupancies)
|
|
153
145
|
except RuntimeError as e:
|
|
154
146
|
raise SystemExit("Error: {}".format(e))
|
|
155
147
|
|
|
148
|
+
if "FREE" in hkldata.df:
|
|
149
|
+
use_in_target = "work"
|
|
150
|
+
if args.use_work_in_est:
|
|
151
|
+
use_in_est = "work"
|
|
152
|
+
else:
|
|
153
|
+
use_in_est = "test"
|
|
154
|
+
else:
|
|
155
|
+
use_in_est = "all"
|
|
156
|
+
use_in_target = "all"
|
|
157
|
+
|
|
156
158
|
is_int = "I" in hkldata.df
|
|
157
159
|
st = sts[0]
|
|
158
160
|
utils.model.fix_deuterium_residues(st)
|
|
159
161
|
if args.unrestrained:
|
|
160
162
|
monlib = gemmi.MonLib()
|
|
161
163
|
topo = None
|
|
164
|
+
h_change = gemmi.HydrogenChange.NoChange
|
|
162
165
|
if args.hydrogen == "all":
|
|
163
|
-
logger.writeln("
|
|
166
|
+
logger.writeln("\nWARNING: in unrestrained refinement hydrogen atoms are not generated.\n")
|
|
164
167
|
elif args.hydrogen == "no":
|
|
165
168
|
st.remove_hydrogens()
|
|
169
|
+
h_change = gemmi.HydrogenChange.Remove
|
|
166
170
|
for i, cra in enumerate(st[0].all()):
|
|
167
171
|
cra.atom.serial = i + 1
|
|
168
172
|
else:
|
|
@@ -172,7 +176,8 @@ def main(args):
|
|
|
172
176
|
params=params)
|
|
173
177
|
except RuntimeError as e:
|
|
174
178
|
raise SystemExit("Error: {}".format(e))
|
|
175
|
-
|
|
179
|
+
if not args.keep_entities:
|
|
180
|
+
utils.model.setup_entities(st, clear=True, force_subchain_names=True, overwrite_entity_type=True)
|
|
176
181
|
utils.restraints.find_and_fix_links(st, monlib, find_metal_links=args.find_links,
|
|
177
182
|
add_found=args.find_links)
|
|
178
183
|
h_change = {"all":gemmi.HydrogenChange.ReAddKnown,
|
|
@@ -185,6 +190,8 @@ def main(args):
|
|
|
185
190
|
except RuntimeError as e:
|
|
186
191
|
raise SystemExit("Error: {}".format(e))
|
|
187
192
|
|
|
193
|
+
print_h_options(h_change, st[0].has_hydrogen(), args.refine_h, args.hout, geom_only=False)
|
|
194
|
+
|
|
188
195
|
# initialize ADP
|
|
189
196
|
utils.model.reset_adp(st[0], args.bfactor, args.adp)
|
|
190
197
|
|
|
@@ -199,7 +206,7 @@ def main(args):
|
|
|
199
206
|
ncslist = utils.restraints.prepare_ncs_restraints(st)
|
|
200
207
|
else:
|
|
201
208
|
ncslist = False
|
|
202
|
-
geom = Geom(st, topo, monlib, shake_rms=args.randomize, adpr_w=args.adpr_weight, params=params,
|
|
209
|
+
geom = Geom(st, topo, monlib, shake_rms=args.randomize, adpr_w=args.adpr_weight, occr_w=args.occr_weight, params=params,
|
|
203
210
|
unrestrained=args.unrestrained or args.jellyonly, use_nucleus=(args.source=="neutron"),
|
|
204
211
|
ncslist=ncslist)
|
|
205
212
|
geom.geom.angle_von_mises = args.vonmises
|
|
@@ -225,7 +232,9 @@ def main(args):
|
|
|
225
232
|
|
|
226
233
|
stats = refiner.run_cycles(args.ncycle, weight=args.weight,
|
|
227
234
|
weight_adjust=not args.no_weight_adjust,
|
|
235
|
+
weight_adjust_bond_rmsz_range=args.target_bond_rmsz_range,
|
|
228
236
|
stats_json_out=args.output_prefix + "_stats.json")
|
|
237
|
+
update_meta(st, stats[-1], ll)
|
|
229
238
|
refiner.st.name = args.output_prefix
|
|
230
239
|
utils.fileio.write_model(refiner.st, args.output_prefix, pdb=True, cif=True, hout=args.hout)
|
|
231
240
|
if params["write_trajectory"]:
|
|
@@ -244,7 +253,7 @@ def main(args):
|
|
|
244
253
|
|
|
245
254
|
# Write mtz file
|
|
246
255
|
if ll.twin_data:
|
|
247
|
-
labs = ["F_est"]
|
|
256
|
+
labs = ["F_est", "F_exp", "FOM"]
|
|
248
257
|
elif is_int:
|
|
249
258
|
labs = ["I", "SIGI", "FOM"]
|
|
250
259
|
else:
|
|
@@ -258,7 +267,7 @@ def main(args):
|
|
|
258
267
|
labs.append("FREE")
|
|
259
268
|
labs += ll.D_labs + ["S"] # for debugging, for now
|
|
260
269
|
mtz_out = args.output_prefix+".mtz"
|
|
261
|
-
hkldata.write_mtz(mtz_out, labs=labs, types={"FOM": "W", "FP":"F", "SIGFP":"Q", "I":"J", "SIGI":"Q", "F_est": "F"})
|
|
270
|
+
hkldata.write_mtz(mtz_out, labs=labs, types={"FOM": "W", "FP":"F", "SIGFP":"Q", "I":"J", "SIGI":"Q", "F_est": "F", "F_exp": "F"})
|
|
262
271
|
|
|
263
272
|
# main()
|
|
264
273
|
|