servalcat 0.4.72__cp312-cp312-macosx_11_0_arm64.whl → 0.4.99__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 +152 -67
- servalcat/refine/refine_geom.py +32 -13
- servalcat/refine/refine_spa.py +70 -40
- servalcat/refine/refine_xtal.py +45 -13
- servalcat/refine/spa.py +15 -4
- servalcat/refine/xtal.py +147 -98
- servalcat/refmac/exte.py +7 -5
- servalcat/refmac/refmac_keywords.py +11 -9
- servalcat/refmac/refmac_wrapper.py +87 -60
- servalcat/spa/fofc.py +20 -3
- servalcat/spa/fsc.py +11 -11
- servalcat/spa/run_refmac.py +27 -12
- servalcat/spa/translate.py +2 -2
- servalcat/utils/commands.py +154 -4
- servalcat/utils/fileio.py +20 -10
- servalcat/utils/hkl.py +43 -29
- servalcat/utils/logger.py +25 -1
- servalcat/utils/maps.py +2 -2
- servalcat/utils/model.py +23 -10
- servalcat/utils/refmac.py +20 -1
- servalcat/utils/restraints.py +34 -25
- servalcat/utils/symmetry.py +5 -5
- servalcat/xtal/french_wilson.py +39 -31
- servalcat/xtal/sigmaa.py +382 -152
- servalcat/xtal/twin.py +121 -0
- {servalcat-0.4.72.dist-info → servalcat-0.4.99.dist-info}/METADATA +4 -4
- servalcat-0.4.99.dist-info/RECORD +45 -0
- {servalcat-0.4.72.dist-info → servalcat-0.4.99.dist-info}/WHEEL +1 -1
- servalcat-0.4.72.dist-info/RECORD +0 -44
- {servalcat-0.4.72.dist-info → servalcat-0.4.99.dist-info}/entry_points.txt +0 -0
- {servalcat-0.4.72.dist-info → servalcat-0.4.99.dist-info}/licenses/LICENSE +0 -0
|
@@ -15,6 +15,7 @@ import tempfile
|
|
|
15
15
|
import subprocess
|
|
16
16
|
import argparse
|
|
17
17
|
from collections import OrderedDict
|
|
18
|
+
import servalcat # for version
|
|
18
19
|
from servalcat.utils import logger
|
|
19
20
|
from servalcat.refmac import refmac_keywords
|
|
20
21
|
from servalcat import utils
|
|
@@ -64,7 +65,7 @@ def read_stdin(stdin):
|
|
|
64
65
|
|
|
65
66
|
def prepare_crd(st, crdout, ligand, make, monlib_path=None, h_pos="elec",
|
|
66
67
|
no_adjust_hydrogen_distances=False, fix_long_resnames=True,
|
|
67
|
-
keep_entities=False):
|
|
68
|
+
keep_entities=False, unre=False):
|
|
68
69
|
assert h_pos in ("elec", "nucl")
|
|
69
70
|
h_change = dict(a=gemmi.HydrogenChange.ReAddButWater,
|
|
70
71
|
y=gemmi.HydrogenChange.NoChange,
|
|
@@ -80,67 +81,85 @@ def prepare_crd(st, crdout, ligand, make, monlib_path=None, h_pos="elec",
|
|
|
80
81
|
if at.occ > 1: # XXX should I check special positions?
|
|
81
82
|
at.occ = 1.
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
refmac_fixes = utils.refmac.FixForRefmac()
|
|
85
|
+
if keep_entities:
|
|
86
|
+
refmac_fixes.store_res_labels(st)
|
|
87
|
+
else:
|
|
84
88
|
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
89
|
|
|
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")
|
|
90
|
+
if unre:
|
|
91
|
+
logger.writeln("Monomer library will not be loaded due to unrestrained refinement request")
|
|
92
|
+
monlib = gemmi.MonLib()
|
|
104
93
|
else:
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
94
|
+
# TODO read dictionary from xyzin (priority: user cif -> monlib -> xyzin
|
|
95
|
+
try:
|
|
96
|
+
monlib = utils.restraints.load_monomer_library(st,
|
|
97
|
+
monomer_dir=monlib_path,
|
|
98
|
+
cif_files=ligand,
|
|
99
|
+
stop_for_unknowns=not make.get("newligand"))
|
|
100
|
+
except RuntimeError as e:
|
|
101
|
+
raise SystemExit("Error: {}".format(e))
|
|
102
|
+
|
|
103
|
+
use_cispeps = make.get("cispept", "y") != "y"
|
|
104
|
+
make_link = make.get("link", "n")
|
|
105
|
+
make_ss = make.get("ss", "y")
|
|
106
|
+
only_from = set()
|
|
107
|
+
if make_link == "y":
|
|
108
|
+
# add all links
|
|
109
|
+
add_found = True
|
|
110
|
+
elif make_ss == "y":
|
|
111
|
+
add_found = True
|
|
112
|
+
only_from.add("disulf")
|
|
113
|
+
else:
|
|
114
|
+
add_found = False
|
|
115
|
+
|
|
116
|
+
utils.restraints.fix_elements_in_model(monlib, st)
|
|
117
|
+
utils.restraints.find_and_fix_links(st, monlib, add_found=add_found,
|
|
118
|
+
find_metal_links=(make_link == "y"),
|
|
119
|
+
find_symmetry_related=False, add_only_from=only_from)
|
|
120
|
+
for con in st.connections:
|
|
121
|
+
if con.link_id not in ("?", "", "gap") and con.link_id not in monlib.links:
|
|
122
|
+
logger.writeln(" removing unknown link id ({}). Ad-hoc link will be generated.".format(con.link_id))
|
|
123
|
+
con.link_id = ""
|
|
113
124
|
|
|
114
|
-
refmac_fixes = utils.refmac.FixForRefmac()
|
|
115
125
|
max_seq_num = max([max(res.seqid.num for res in chain) for model in st for chain in model])
|
|
116
126
|
if max_seq_num > 9999:
|
|
117
127
|
logger.writeln("Max residue number ({}) exceeds 9999. Needs workaround.".format(max_seq_num))
|
|
118
|
-
topo = gemmi.prepare_topology(st, monlib, ignore_unknown_links=True)
|
|
128
|
+
topo = gemmi.prepare_topology(st, monlib, warnings=logger.silent(), ignore_unknown_links=True)
|
|
119
129
|
refmac_fixes.fix_before_topology(st, topo,
|
|
120
130
|
fix_microheterogeneity=False,
|
|
121
131
|
fix_resimax=True,
|
|
122
132
|
fix_nonpolymer=False)
|
|
123
133
|
|
|
124
|
-
if
|
|
125
|
-
|
|
126
|
-
topo
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
134
|
+
if unre:
|
|
135
|
+
# Refmac5 does not seem to do anything to hydrogen when unre regardless of "make hydr"
|
|
136
|
+
topo = gemmi.prepare_topology(st, monlib, warnings=logger.silent(), ignore_unknown_links=True)
|
|
137
|
+
metal_kws = []
|
|
138
|
+
else:
|
|
139
|
+
if make.get("hydr") == "a": logger.writeln("(re)generating hydrogen atoms")
|
|
140
|
+
try:
|
|
141
|
+
topo, metal_kws = utils.restraints.prepare_topology(st, monlib, h_change=h_change, ignore_unknown_links=False,
|
|
142
|
+
check_hydrogen=(h_change==gemmi.HydrogenChange.NoChange),
|
|
143
|
+
use_cispeps=use_cispeps)
|
|
144
|
+
except RuntimeError as e:
|
|
145
|
+
raise SystemExit("Error: {}".format(e))
|
|
131
146
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
147
|
+
if make.get("hydr") != "n" and st[0].has_hydrogen():
|
|
148
|
+
if h_pos == "nucl" and (make.get("hydr") == "a" or not no_adjust_hydrogen_distances):
|
|
149
|
+
resnames = st[0].get_all_residue_names()
|
|
150
|
+
utils.restraints.check_monlib_support_nucleus_distances(monlib, resnames)
|
|
151
|
+
logger.writeln("adjusting hydrogen position to nucleus")
|
|
152
|
+
topo.adjust_hydrogen_distances(gemmi.Restraints.DistanceOf.Nucleus, default_scale=1.1)
|
|
153
|
+
elif h_pos == "elec" and make.get("hydr") == "y" and not no_adjust_hydrogen_distances:
|
|
154
|
+
logger.writeln("adjusting hydrogen position to electron cloud")
|
|
155
|
+
topo.adjust_hydrogen_distances(gemmi.Restraints.DistanceOf.ElectronCloud)
|
|
141
156
|
|
|
142
157
|
if fix_long_resnames: refmac_fixes.fix_long_resnames(st)
|
|
143
158
|
|
|
159
|
+
# remove "given" ncs matrices
|
|
160
|
+
# TODO write them back to the output files
|
|
161
|
+
st.ncs = gemmi.NcsOpList(x for x in st.ncs if not x.given)
|
|
162
|
+
|
|
144
163
|
# for safety
|
|
145
164
|
if "_entry.id" in st.info:
|
|
146
165
|
st.info["_entry.id"] = st.info["_entry.id"].replace(" ", "")
|
|
@@ -172,7 +191,7 @@ def prepare_crd(st, crdout, ligand, make, monlib_path=None, h_pos="elec",
|
|
|
172
191
|
if st.name.lower() in block_names:
|
|
173
192
|
st.name = st.name + str(i)
|
|
174
193
|
doc = gemmi.prepare_refmac_crd(st, topo, monlib, h_change)
|
|
175
|
-
doc.write_file(crdout,
|
|
194
|
+
doc.write_file(crdout, options=gemmi.cif.Style.NoBlankLines)
|
|
176
195
|
logger.writeln("crd file written: {}".format(crdout))
|
|
177
196
|
return refmac_fixes, [x+"\n" for x in metal_kws]
|
|
178
197
|
# prepare_crd()
|
|
@@ -221,11 +240,22 @@ def modify_output(pdbout, cifout, fixes, hout, cispeps, keep_original_output=Fal
|
|
|
221
240
|
# should we check metals and put MetalC?
|
|
222
241
|
|
|
223
242
|
# fix entity (Refmac seems to make DNA non-polymer; as seen in 1fix)
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
243
|
+
if not fixes or not fixes.res_labels:
|
|
244
|
+
utils.model.setup_entities(st, clear=True, overwrite_entity_type=True, force_subchain_names=True)
|
|
245
|
+
for e in st.entities:
|
|
246
|
+
if not e.full_sequence and e.entity_type == gemmi.EntityType.Polymer and e.subchains:
|
|
247
|
+
rspan = st[0].get_subchain(e.subchains[0])
|
|
248
|
+
e.full_sequence = [r.name for r in rspan]
|
|
249
|
+
|
|
250
|
+
# fix label_seq_id
|
|
251
|
+
for chain in st[0]:
|
|
252
|
+
for res in chain:
|
|
253
|
+
res.label_seq = None
|
|
254
|
+
st.assign_label_seq_id()
|
|
255
|
+
|
|
256
|
+
# add servalcat version
|
|
257
|
+
if len(st.meta.software) > 0 and st.meta.software[-1].name == "refmac":
|
|
258
|
+
st.meta.software[-1].version += f" (refmacat {servalcat.__version__})"
|
|
229
259
|
|
|
230
260
|
suffix = ".org"
|
|
231
261
|
os.rename(cifout, cifout + suffix)
|
|
@@ -243,11 +273,6 @@ def modify_output(pdbout, cifout, fixes, hout, cispeps, keep_original_output=Fal
|
|
|
243
273
|
logger.writeln("This structure cannot be saved as an official PDB format. Using hybrid-36. Header part may be inaccurate.")
|
|
244
274
|
if not hout:
|
|
245
275
|
st.remove_hydrogens() # remove hydrogen from pdb, while kept in mmcif
|
|
246
|
-
# Use short name in pdb
|
|
247
|
-
st.shorten_ccd_codes()
|
|
248
|
-
if st.shortened_ccd_codes:
|
|
249
|
-
msg = " ".join("{}->{}".format(o,n) for o,n in st.shortened_ccd_codes)
|
|
250
|
-
logger.writeln("Using shortened residue names in the output pdb file: " + msg)
|
|
251
276
|
os.rename(pdbout, pdbout + suffix)
|
|
252
277
|
utils.fileio.write_pdb(st, pdbout)
|
|
253
278
|
if not keep_original_output:
|
|
@@ -292,11 +317,12 @@ def main(args):
|
|
|
292
317
|
crdout = None
|
|
293
318
|
refmac_fixes = None
|
|
294
319
|
cispeps = []
|
|
295
|
-
|
|
320
|
+
unre = keywords["refi"].get("type") == "unre"
|
|
321
|
+
if xyzin is not None:
|
|
296
322
|
#tmpfd, crdout = tempfile.mkstemp(prefix="gemmi_", suffix=".crd") # TODO use dir=CCP4_SCR
|
|
297
323
|
#os.close(tmpfd)
|
|
298
324
|
st = utils.fileio.read_structure(xyzin)
|
|
299
|
-
if not st.cell.is_crystal():
|
|
325
|
+
if not st.cell.is_crystal() and not unre:
|
|
300
326
|
if args.auto_box_with_padding is not None:
|
|
301
327
|
st.cell = utils.model.box_from_model(st[0], args.auto_box_with_padding)
|
|
302
328
|
st.spacegroup_hm = "P 1"
|
|
@@ -309,7 +335,8 @@ def main(args):
|
|
|
309
335
|
refmac_fixes, metal_kws = prepare_crd(st, crdout, args.ligand, make=keywords["make"], monlib_path=args.monlib,
|
|
310
336
|
h_pos="nucl" if keywords.get("source")=="ne" else "elec",
|
|
311
337
|
no_adjust_hydrogen_distances=args.no_adjust_hydrogen_distances,
|
|
312
|
-
keep_entities=args.keep_entities
|
|
338
|
+
keep_entities=args.keep_entities,
|
|
339
|
+
unre=unre)
|
|
313
340
|
inputs = metal_kws + inputs # add metal exte first; otherwise it may be affected by user-defined inputs
|
|
314
341
|
opts["xyzin"] = crdout
|
|
315
342
|
cispeps = st.cispeps
|
servalcat/spa/fofc.py
CHANGED
|
@@ -44,9 +44,11 @@ def add_arguments(parser):
|
|
|
44
44
|
parser.add_argument("--monlib",
|
|
45
45
|
help="Monomer library path. Default: $CLIBD_MON")
|
|
46
46
|
parser.add_argument("--omit_proton", action='store_true',
|
|
47
|
-
help="Omit proton from model in map calculation")
|
|
47
|
+
#help="Omit hydrogen proton (leaving electrons) from model in map calculation")
|
|
48
|
+
help=argparse.SUPPRESS)
|
|
48
49
|
parser.add_argument("--omit_h_electron", action='store_true',
|
|
49
|
-
help="Omit hydrogen electrons from model in map calculation")
|
|
50
|
+
#help="Omit hydrogen electrons (leaving protons) from model in map calculation")
|
|
51
|
+
help=argparse.SUPPRESS)
|
|
50
52
|
parser.add_argument("--source", choices=["electron", "xray", "neutron"], default="electron")
|
|
51
53
|
parser.add_argument('-o','--output_prefix', default="diffmap",
|
|
52
54
|
help='output file name prefix (default: %(default)s)')
|
|
@@ -377,6 +379,17 @@ def write_coot_script(py_out, model_file, mtz_file, contour_fo=1.2, contour_fofc
|
|
|
377
379
|
ofs.write("add_molecular_symmetry(imol, {})\n".format(",".join(str(x) for x in v)))
|
|
378
380
|
# write_coot_script()
|
|
379
381
|
|
|
382
|
+
def write_chimerax_script(cxc_out, model_file, fo_mrc_file, fofc_mrc_file):
|
|
383
|
+
with open(cxc_out, "w") as ofs:
|
|
384
|
+
ofs.write('open {}\n'.format(model_file))
|
|
385
|
+
ofs.write('open {}\n'.format(fo_mrc_file))
|
|
386
|
+
ofs.write('open {}\n'.format(fofc_mrc_file))
|
|
387
|
+
ofs.write('volume #3 level 4 level -4 color #00FF00 color #FF0000 squaremesh false cap false style mesh meshlighting false\n')
|
|
388
|
+
ofs.write('isolde start\n')
|
|
389
|
+
ofs.write('clipper associate #2 toModel #1\n')
|
|
390
|
+
ofs.write('clipper associate #3 toModel #1\n')
|
|
391
|
+
# write_chimerax_script()
|
|
392
|
+
|
|
380
393
|
def main(args):
|
|
381
394
|
if not args.halfmaps and not args.map:
|
|
382
395
|
raise SystemExit("Error: give --halfmaps or --map")
|
|
@@ -453,7 +466,11 @@ def main(args):
|
|
|
453
466
|
logger.writeln("coot --script " + py_out)
|
|
454
467
|
if mask is not None:
|
|
455
468
|
logger.writeln("\nWant to list Fo-Fc map peaks? Try:")
|
|
456
|
-
|
|
469
|
+
if omit_h_electron:
|
|
470
|
+
logger.writeln("servalcat util map_peaks --map {}_normalized_fofc_flipsign.mrc --model {} --abs_level 4.0".format(args.output_prefix, args.model))
|
|
471
|
+
else:
|
|
472
|
+
logger.writeln("servalcat util map_peaks --map {}_normalized_fofc.mrc --model {} --abs_level 4.0".format(args.output_prefix, args.model))
|
|
473
|
+
|
|
457
474
|
# main()
|
|
458
475
|
|
|
459
476
|
if __name__ == "__main__":
|
servalcat/spa/fsc.py
CHANGED
|
@@ -20,13 +20,14 @@ def add_arguments(parser):
|
|
|
20
20
|
|
|
21
21
|
parser.add_argument('--model',
|
|
22
22
|
help="")
|
|
23
|
-
parser.
|
|
23
|
+
group = parser.add_mutually_exclusive_group(required=True)
|
|
24
|
+
group.add_argument('--map',
|
|
24
25
|
help='Input map file(s)')
|
|
25
|
-
|
|
26
|
+
group.add_argument("--halfmaps", nargs=2)
|
|
27
|
+
group.add_argument('--mtz',
|
|
26
28
|
help='Input mtz file.')
|
|
27
29
|
parser.add_argument('--labin', nargs=2,
|
|
28
30
|
help='label (F and PHI) for mtz')
|
|
29
|
-
parser.add_argument("--halfmaps", nargs=2)
|
|
30
31
|
parser.add_argument('--pixel_size', type=float,
|
|
31
32
|
help='Override pixel size (A)')
|
|
32
33
|
parser.add_argument('--mask', help='Mask file')
|
|
@@ -36,6 +37,8 @@ def add_arguments(parser):
|
|
|
36
37
|
parser.add_argument('--mask_soft_edge',
|
|
37
38
|
type=float, default=0,
|
|
38
39
|
help='Add soft edge to model mask.')
|
|
40
|
+
parser.add_argument('--mask_model', action='store_true',
|
|
41
|
+
help='Apply mask to model density')
|
|
39
42
|
parser.add_argument("--b_before_mask", type=float,
|
|
40
43
|
help="when model-based mask is used: sharpening B value for sharpen-mask-unsharpen procedure. By default it is determined automatically.")
|
|
41
44
|
parser.add_argument('--no_sharpen_before_mask', action='store_true',
|
|
@@ -66,13 +69,10 @@ def write_loggraph(stats, labs_fc, log_out):
|
|
|
66
69
|
model_labs1 = [l for l in stats if any(l.startswith("fsc_"+fc) for fc in labs_fc)]
|
|
67
70
|
model_labs2 = [l for l in stats if any(l.startswith(("cc_"+fc, "mcos_"+fc)) for fc in labs_fc)]
|
|
68
71
|
power_labs = [l for l in stats if l.startswith("power_")]
|
|
69
|
-
half_labs1 = ["fsc_half_unmasked", "fsc_half_masked", "fsc_half_masked_rand", "fsc_half_masked_corrected"]
|
|
70
|
-
half_labs2 = ["cc_half", "mcos_half"]
|
|
71
|
-
if not
|
|
72
|
-
|
|
73
|
-
half_labs1 = ["fsc_half"]
|
|
74
|
-
else:
|
|
75
|
-
half_labs1 = []
|
|
72
|
+
half_labs1 = [l for l in ("fsc_half_unmasked", "fsc_half_masked", "fsc_half_masked_rand", "fsc_half_masked_corrected") if l in stats]
|
|
73
|
+
half_labs2 = [l for l in ("cc_half", "mcos_half") if l in stats]
|
|
74
|
+
if not half_labs1 and "fsc_half" in stats:
|
|
75
|
+
half_labs1 = ["fsc_half"]
|
|
76
76
|
|
|
77
77
|
stats2 = stats.copy()
|
|
78
78
|
stats2.insert(0, "bin", stats.index)
|
|
@@ -340,7 +340,7 @@ def main(args):
|
|
|
340
340
|
labs_fc.append("FC")
|
|
341
341
|
hkldata.df[labs_fc[-1]] = utils.model.calc_fc_fft(st_expanded, args.resolution - 1e-6, source="electron",
|
|
342
342
|
miller_array=hkldata.miller_array())
|
|
343
|
-
if mask is not None:
|
|
343
|
+
if args.mask_model and mask is not None:
|
|
344
344
|
if args.b_before_mask is None:
|
|
345
345
|
normalizer = 1.
|
|
346
346
|
else:
|
servalcat/spa/run_refmac.py
CHANGED
|
@@ -10,7 +10,6 @@ import gemmi
|
|
|
10
10
|
import numpy
|
|
11
11
|
import json
|
|
12
12
|
import os
|
|
13
|
-
import io
|
|
14
13
|
import shutil
|
|
15
14
|
import argparse
|
|
16
15
|
from servalcat.utils import logger
|
|
@@ -58,7 +57,7 @@ def add_arguments(parser):
|
|
|
58
57
|
help='Sharpening or blurring B')
|
|
59
58
|
utils.symmetry.add_symmetry_args(parser) # add --pg etc
|
|
60
59
|
parser.add_argument('--contacting_only', action="store_true", help="Filter out non-contacting NCS")
|
|
61
|
-
parser.add_argument('--ignore_symmetry',
|
|
60
|
+
parser.add_argument('--ignore_symmetry', action='store_true',
|
|
62
61
|
help='Ignore symmetry information (MTRIX/_struct_ncs_oper) in the model file')
|
|
63
62
|
parser.add_argument('--find_links', action='store_true',
|
|
64
63
|
help='Automatically add links')
|
|
@@ -150,6 +149,7 @@ def calc_fsc(st, output_prefix, maps, d_min, mask, mask_radius, soft_edge, b_bef
|
|
|
150
149
|
assert st_sr is None
|
|
151
150
|
|
|
152
151
|
logger.writeln("Calculating map-model FSC..")
|
|
152
|
+
ret = {"summary": {}}
|
|
153
153
|
|
|
154
154
|
if d_min_fsc is None:
|
|
155
155
|
d_min_fsc = utils.maps.nyquist_resolution(maps[0][0])
|
|
@@ -220,12 +220,17 @@ def calc_fsc(st, output_prefix, maps, d_min, mask, mask_radius, soft_edge, b_bef
|
|
|
220
220
|
s.drop(columns=[x for x in s if x.startswith("fsc_FC") and x.endswith(("half1","half2"))], inplace=True)
|
|
221
221
|
|
|
222
222
|
# FSCaverages
|
|
223
|
+
ret["summary"]["d_min"] = d_min
|
|
224
|
+
ret["summary"]["FSCaverage"] = spa.fsc.fsc_average(stats2.ncoeffs, stats2.fsc_model)
|
|
225
|
+
if cross_validation:
|
|
226
|
+
ret["summary"]["FSCaverage_half1"] = spa.fsc.fsc_average(stats2.ncoeffs, stats2.fsc_model_half1)
|
|
227
|
+
ret["summary"]["FSCaverage_half2"] = spa.fsc.fsc_average(stats2.ncoeffs, stats2.fsc_model_half2)
|
|
223
228
|
fscavg_text = "Map-model FSCaverages (at {:.2f} A):\n".format(d_min)
|
|
224
|
-
fscavg_text += " FSCaverage(full) = {: .4f}\n".format(
|
|
229
|
+
fscavg_text += " FSCaverage(full) = {: .4f}\n".format(ret["summary"]["FSCaverage"])
|
|
225
230
|
if cross_validation:
|
|
226
231
|
fscavg_text += "Cross-validated map-model FSCaverages:\n"
|
|
227
|
-
fscavg_text += " FSCaverage(half1)= {: .4f}\n".format(
|
|
228
|
-
fscavg_text += " FSCaverage(half2)= {: .4f}\n".format(
|
|
232
|
+
fscavg_text += " FSCaverage(half1)= {: .4f}\n".format(ret["summary"]["FSCaverage_half1"])
|
|
233
|
+
fscavg_text += " FSCaverage(half2)= {: .4f}\n".format(ret["summary"]["FSCaverage_half2"])
|
|
229
234
|
|
|
230
235
|
# for loggraph
|
|
231
236
|
fsc_logfile = "{}_fsc.log".format(output_prefix)
|
|
@@ -269,8 +274,8 @@ def calc_fsc(st, output_prefix, maps, d_min, mask, mask_radius, soft_edge, b_bef
|
|
|
269
274
|
json.dump(stats.to_dict("records"),
|
|
270
275
|
open("{}_fsc.json".format(output_prefix), "w"),
|
|
271
276
|
indent=True)
|
|
272
|
-
|
|
273
|
-
return fscavg_text
|
|
277
|
+
ret["binned"] = stats2.to_dict(orient="records")
|
|
278
|
+
return fscavg_text, ret
|
|
274
279
|
# calc_fsc()
|
|
275
280
|
|
|
276
281
|
def calc_fofc(st, st_expanded, maps, monlib, model_format, args, diffmap_prefix="diffmap"):
|
|
@@ -311,6 +316,12 @@ def calc_fofc(st, st_expanded, maps, monlib, model_format, args, diffmap_prefix=
|
|
|
311
316
|
contour_fo=None if mask is None else 1.2,
|
|
312
317
|
contour_fofc=None if mask is None else 3.0,
|
|
313
318
|
ncs_ops=st.ncs)
|
|
319
|
+
|
|
320
|
+
# Create ChimeraX script
|
|
321
|
+
spa.fofc.write_chimerax_script(cxc_out="{}_chimerax.cxc".format(args.output_prefix),
|
|
322
|
+
model_file="{}.mmcif".format(args.output_prefix), # ChimeraX handles mmcif just fine
|
|
323
|
+
fo_mrc_file="{}_normalized_fo.mrc".format(diffmap_prefix),
|
|
324
|
+
fofc_mrc_file="{}_normalized_fofc.mrc".format(diffmap_prefix))
|
|
314
325
|
# calc_fofc()
|
|
315
326
|
|
|
316
327
|
def write_final_summary(st, refmac_summary, fscavg_text, output_prefix, is_mask_given):
|
|
@@ -356,6 +367,9 @@ Weight used: {final_weight}
|
|
|
356
367
|
Open refined model and diffmap.mtz with COOT:
|
|
357
368
|
coot --script {prefix}_coot.py
|
|
358
369
|
|
|
370
|
+
Open refined model, map and difference map with ChimeraX/ISOLDE:
|
|
371
|
+
chimerax {prefix}_chimerax.cxc
|
|
372
|
+
|
|
359
373
|
{map_peaks_msg}
|
|
360
374
|
=============================================================================
|
|
361
375
|
""".format(rmsbond=refmac_summary["cycles"][-1].get("rms_bond", "???"),
|
|
@@ -453,7 +467,7 @@ def process_input(st, maps, resolution, monlib, mask_in, args,
|
|
|
453
467
|
unit_cell = maps[0][0].unit_cell
|
|
454
468
|
spacegroup = gemmi.SpaceGroup(1)
|
|
455
469
|
start_xyz = numpy.array(maps[0][0].get_position(*grid_start).tolist())
|
|
456
|
-
A =
|
|
470
|
+
A = unit_cell.orth.mat.array
|
|
457
471
|
center = numpy.sum(A, axis=1) / 2 #+ start_xyz
|
|
458
472
|
|
|
459
473
|
# Create mask
|
|
@@ -584,7 +598,7 @@ def process_input(st, maps, resolution, monlib, mask_in, args,
|
|
|
584
598
|
topo, metal_kws = utils.restraints.prepare_topology(st, monlib, h_change=h_change, raise_error=False)
|
|
585
599
|
args.keywords = metal_kws + args.keywords
|
|
586
600
|
elif not no_refmac_fix:
|
|
587
|
-
topo = gemmi.prepare_topology(st, monlib, warnings=
|
|
601
|
+
topo = gemmi.prepare_topology(st, monlib, warnings=logger.silent(), ignore_unknown_links=True)
|
|
588
602
|
else:
|
|
589
603
|
topo = None # not used
|
|
590
604
|
if not no_refmac_fix:
|
|
@@ -609,7 +623,7 @@ def process_input(st, maps, resolution, monlib, mask_in, args,
|
|
|
609
623
|
args.keywords.append("make cr prepared")
|
|
610
624
|
gemmi.setup_for_crd(st)
|
|
611
625
|
doc = gemmi.prepare_refmac_crd(st, topo, monlib, h_change)
|
|
612
|
-
doc.write_file(crdout,
|
|
626
|
+
doc.write_file(crdout, options=gemmi.cif.Style.NoBlankLines)
|
|
613
627
|
logger.writeln("crd file written: {}".format(crdout))
|
|
614
628
|
|
|
615
629
|
hkldata = utils.maps.mask_and_fft_maps(maps, resolution, None, with_000=False)
|
|
@@ -681,8 +695,9 @@ def check_args(args):
|
|
|
681
695
|
if args.keyword_file:
|
|
682
696
|
args.keyword_file = sum(args.keyword_file, [])
|
|
683
697
|
for f in args.keyword_file:
|
|
698
|
+
if not os.path.exists(f):
|
|
699
|
+
raise SystemExit(f"Error: keyword file was not found: {f}")
|
|
684
700
|
logger.writeln("Keyword file: {}".format(f))
|
|
685
|
-
assert os.path.exists(f)
|
|
686
701
|
else:
|
|
687
702
|
args.keyword_file = []
|
|
688
703
|
|
|
@@ -945,7 +960,7 @@ def main(args):
|
|
|
945
960
|
monlib=monlib, cross_validation=args.cross_validation,
|
|
946
961
|
blur=args.blur,
|
|
947
962
|
d_min_fsc=args.fsc_resolution,
|
|
948
|
-
cross_validation_method=args.cross_validation_method, st_sr=st_sr_expanded)
|
|
963
|
+
cross_validation_method=args.cross_validation_method, st_sr=st_sr_expanded)[0]
|
|
949
964
|
|
|
950
965
|
# Calc Fo-Fc (and updated) maps
|
|
951
966
|
calc_fofc(st, st_expanded, maps, monlib, model_format, args)
|
servalcat/spa/translate.py
CHANGED
|
@@ -60,9 +60,9 @@ def find_peak(tf_map, ini_pos):
|
|
|
60
60
|
|
|
61
61
|
x = tf_map.unit_cell.fractionalize(ini_pos)
|
|
62
62
|
logger.writeln(" x0: [{}, {}, {}]".format(*x.tolist()))
|
|
63
|
-
logger.writeln(" f0: {}".format(-tf_map.
|
|
63
|
+
logger.writeln(" f0: {}".format(-tf_map.interpolate_value(x, order=3)))
|
|
64
64
|
|
|
65
|
-
res = scipy.optimize.minimize(fun=lambda x:-tf_map.
|
|
65
|
+
res = scipy.optimize.minimize(fun=lambda x:-tf_map.interpolate_value(gemmi.Fractional(*x), order=3),
|
|
66
66
|
x0=x.tolist(),
|
|
67
67
|
jac=lambda x:-numpy.array(tf_map.tricubic_interpolation_der(gemmi.Fractional(*x))[1:]))
|
|
68
68
|
logger.writeln(str(res))
|