servalcat 0.4.131__cp314-cp314t-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- servalcat/__init__.py +10 -0
- servalcat/__main__.py +120 -0
- servalcat/ext.cpython-314t-x86_64-linux-gnu.so +0 -0
- servalcat/refine/__init__.py +0 -0
- servalcat/refine/cgsolve.py +100 -0
- servalcat/refine/refine.py +1162 -0
- servalcat/refine/refine_geom.py +245 -0
- servalcat/refine/refine_spa.py +400 -0
- servalcat/refine/refine_xtal.py +339 -0
- servalcat/refine/spa.py +151 -0
- servalcat/refine/xtal.py +312 -0
- servalcat/refmac/__init__.py +0 -0
- servalcat/refmac/exte.py +191 -0
- servalcat/refmac/refmac_keywords.py +660 -0
- servalcat/refmac/refmac_wrapper.py +423 -0
- servalcat/spa/__init__.py +0 -0
- servalcat/spa/fofc.py +488 -0
- servalcat/spa/fsc.py +391 -0
- servalcat/spa/localcc.py +197 -0
- servalcat/spa/realspcc_from_var.py +128 -0
- servalcat/spa/run_refmac.py +979 -0
- servalcat/spa/shift_maps.py +293 -0
- servalcat/spa/shiftback.py +137 -0
- servalcat/spa/translate.py +129 -0
- servalcat/utils/__init__.py +35 -0
- servalcat/utils/commands.py +1629 -0
- servalcat/utils/fileio.py +836 -0
- servalcat/utils/generate_operators.py +296 -0
- servalcat/utils/hkl.py +811 -0
- servalcat/utils/logger.py +140 -0
- servalcat/utils/maps.py +345 -0
- servalcat/utils/model.py +933 -0
- servalcat/utils/refmac.py +759 -0
- servalcat/utils/restraints.py +888 -0
- servalcat/utils/symmetry.py +298 -0
- servalcat/xtal/__init__.py +0 -0
- servalcat/xtal/french_wilson.py +262 -0
- servalcat/xtal/run_refmac_small.py +240 -0
- servalcat/xtal/sigmaa.py +1954 -0
- servalcat/xtal/twin.py +316 -0
- servalcat-0.4.131.dist-info/METADATA +60 -0
- servalcat-0.4.131.dist-info/RECORD +45 -0
- servalcat-0.4.131.dist-info/WHEEL +6 -0
- servalcat-0.4.131.dist-info/entry_points.txt +4 -0
- servalcat-0.4.131.dist-info/licenses/LICENSE +373 -0
|
@@ -0,0 +1,423 @@
|
|
|
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 os
|
|
13
|
+
import sys
|
|
14
|
+
import tempfile
|
|
15
|
+
import subprocess
|
|
16
|
+
import argparse
|
|
17
|
+
from collections import OrderedDict
|
|
18
|
+
import servalcat # for version
|
|
19
|
+
from servalcat.utils import logger
|
|
20
|
+
from servalcat.refmac import refmac_keywords
|
|
21
|
+
from servalcat import utils
|
|
22
|
+
|
|
23
|
+
def add_arguments(parser):
|
|
24
|
+
parser.description = 'Run REFMAC5 with gemmi-prepared restraints'
|
|
25
|
+
parser.add_argument('--exe', default="refmac5", help='refmac5 binary')
|
|
26
|
+
parser.add_argument("--monlib",
|
|
27
|
+
help="Monomer library path. Default: $CLIBD_MON")
|
|
28
|
+
parser.add_argument('--ligand', nargs="*", action="append")
|
|
29
|
+
parser.add_argument("opts", nargs="+",
|
|
30
|
+
help="HKLIN hklin XYZIN xyzin...")
|
|
31
|
+
parser.add_argument('--auto_box_with_padding', type=float, help="Determine box size from model with specified padding")
|
|
32
|
+
parser.add_argument('--no_adjust_hydrogen_distances', action='store_true', help="By default it adjusts hydrogen distances using ideal values. This option is to disable it.")
|
|
33
|
+
parser.add_argument('--keep_original_output', action='store_true', help="with .org extension")
|
|
34
|
+
parser.add_argument("--keep_entities", action='store_true',
|
|
35
|
+
help="Do not override entities")
|
|
36
|
+
parser.add_argument("--tls_addu", action='store_true',
|
|
37
|
+
help="Write prefix_addu.mmcif where TLS contribution is added to aniso U. Don't use this with 'tlso addu' keyword.")
|
|
38
|
+
parser.add_argument('--prefix', help="output prefix")
|
|
39
|
+
parser.add_argument("-v", "--version", action="version",
|
|
40
|
+
version=logger.versions_str())
|
|
41
|
+
# TODO --cell to override unit cell?
|
|
42
|
+
|
|
43
|
+
# add_arguments()
|
|
44
|
+
|
|
45
|
+
def parse_args(arg_list):
|
|
46
|
+
parser = argparse.ArgumentParser()
|
|
47
|
+
add_arguments(parser)
|
|
48
|
+
return parser.parse_args(arg_list)
|
|
49
|
+
# parse_args()
|
|
50
|
+
|
|
51
|
+
def read_stdin(stdin):
|
|
52
|
+
print("Waiting for input..")
|
|
53
|
+
# these make keywords will be ignored (just passed to refmac): ribo,valu,spec,form,sdmi,segi
|
|
54
|
+
ret = {"make":{}, "ridge":{}, "refi":{}}
|
|
55
|
+
inputs = []
|
|
56
|
+
for l in refmac_keywords.get_lines(stdin):
|
|
57
|
+
refmac_keywords.parse_line(l, ret, raise_unknown=False)
|
|
58
|
+
inputs.append(l + "\n")
|
|
59
|
+
|
|
60
|
+
def sorry(s): raise SystemExit("Sorry, '{}' is not supported".format(s))
|
|
61
|
+
if ret["make"].get("hydr") == "f":
|
|
62
|
+
sorry("make hydr full")
|
|
63
|
+
if ret["make"].get("buil") == "y":
|
|
64
|
+
sorry("make build yes")
|
|
65
|
+
return inputs, ret
|
|
66
|
+
# read_stdin()
|
|
67
|
+
|
|
68
|
+
def prepare_crd(st, crdout, ligand, make, monlib_path=None, h_pos="elec",
|
|
69
|
+
no_adjust_hydrogen_distances=False, fix_long_resnames=True,
|
|
70
|
+
keep_entities=False, unre=False):
|
|
71
|
+
assert h_pos in ("elec", "nucl")
|
|
72
|
+
h_change = dict(a=gemmi.HydrogenChange.ReAddButWater,
|
|
73
|
+
y=gemmi.HydrogenChange.NoChange,
|
|
74
|
+
n=gemmi.HydrogenChange.Remove)[make.get("hydr", "a")]
|
|
75
|
+
utils.model.fix_deuterium_residues(st)
|
|
76
|
+
for chain in st[0]:
|
|
77
|
+
if not chain.name:
|
|
78
|
+
chain.name = "X" # Refmac behavior. Empty chain name will cause a problem
|
|
79
|
+
for res in chain:
|
|
80
|
+
if res.is_water():
|
|
81
|
+
res.name = "HOH"
|
|
82
|
+
for at in res:
|
|
83
|
+
if at.occ > 1: # XXX should I check special positions?
|
|
84
|
+
at.occ = 1.
|
|
85
|
+
|
|
86
|
+
refmac_fixes = utils.refmac.FixForRefmac()
|
|
87
|
+
if keep_entities:
|
|
88
|
+
refmac_fixes.store_res_labels(st)
|
|
89
|
+
else:
|
|
90
|
+
utils.model.setup_entities(st, clear=True, force_subchain_names=True, overwrite_entity_type=True)
|
|
91
|
+
|
|
92
|
+
if unre:
|
|
93
|
+
logger.writeln("Monomer library will not be loaded due to unrestrained refinement request")
|
|
94
|
+
monlib = gemmi.MonLib()
|
|
95
|
+
else:
|
|
96
|
+
# TODO read dictionary from xyzin (priority: user cif -> monlib -> xyzin
|
|
97
|
+
try:
|
|
98
|
+
monlib = utils.restraints.load_monomer_library(st,
|
|
99
|
+
monomer_dir=monlib_path,
|
|
100
|
+
cif_files=ligand,
|
|
101
|
+
stop_for_unknowns=not make.get("newligand"))
|
|
102
|
+
except RuntimeError as e:
|
|
103
|
+
raise SystemExit("Error: {}".format(e))
|
|
104
|
+
|
|
105
|
+
use_cispeps = make.get("cispept", "y") != "y"
|
|
106
|
+
make_link = make.get("link", "n")
|
|
107
|
+
make_ss = make.get("ss", "y")
|
|
108
|
+
only_from = set()
|
|
109
|
+
if make_link == "y":
|
|
110
|
+
# add all links
|
|
111
|
+
add_found = True
|
|
112
|
+
elif make_ss == "y":
|
|
113
|
+
add_found = True
|
|
114
|
+
only_from.add("disulf")
|
|
115
|
+
else:
|
|
116
|
+
add_found = False
|
|
117
|
+
|
|
118
|
+
utils.restraints.fix_elements_in_model(monlib, st)
|
|
119
|
+
utils.restraints.find_and_fix_links(st, monlib, add_found=add_found,
|
|
120
|
+
find_metal_links=(make_link == "y"),
|
|
121
|
+
find_symmetry_related=False, add_only_from=only_from)
|
|
122
|
+
for con in st.connections:
|
|
123
|
+
if con.link_id not in ("?", "", "gap") and con.link_id not in monlib.links:
|
|
124
|
+
logger.writeln(" removing unknown link id ({}). Ad-hoc link will be generated.".format(con.link_id))
|
|
125
|
+
con.link_id = ""
|
|
126
|
+
|
|
127
|
+
max_seq_num = max([max(res.seqid.num for res in chain) for model in st for chain in model])
|
|
128
|
+
if max_seq_num > 9999:
|
|
129
|
+
logger.writeln("Max residue number ({}) exceeds 9999. Needs workaround.".format(max_seq_num))
|
|
130
|
+
topo = gemmi.prepare_topology(st, monlib, warnings=logger.silent(), ignore_unknown_links=True)
|
|
131
|
+
refmac_fixes.fix_before_topology(st, topo,
|
|
132
|
+
fix_microheterogeneity=False,
|
|
133
|
+
fix_resimax=True,
|
|
134
|
+
fix_nonpolymer=False)
|
|
135
|
+
|
|
136
|
+
if unre:
|
|
137
|
+
# Refmac5 does not seem to do anything to hydrogen when unre regardless of "make hydr"
|
|
138
|
+
topo = gemmi.prepare_topology(st, monlib, warnings=logger.silent(), ignore_unknown_links=True)
|
|
139
|
+
metal_kws = []
|
|
140
|
+
else:
|
|
141
|
+
if make.get("hydr") == "a": logger.writeln("(re)generating hydrogen atoms")
|
|
142
|
+
try:
|
|
143
|
+
topo, metal_kws = utils.restraints.prepare_topology(st, monlib, h_change=h_change, ignore_unknown_links=False,
|
|
144
|
+
check_hydrogen=(h_change==gemmi.HydrogenChange.NoChange),
|
|
145
|
+
use_cispeps=use_cispeps)
|
|
146
|
+
except RuntimeError as e:
|
|
147
|
+
raise SystemExit("Error: {}".format(e))
|
|
148
|
+
|
|
149
|
+
if make.get("hydr") != "n" and st[0].has_hydrogen():
|
|
150
|
+
if h_pos == "nucl" and (make.get("hydr") == "a" or not no_adjust_hydrogen_distances):
|
|
151
|
+
resnames = st[0].get_all_residue_names()
|
|
152
|
+
utils.restraints.check_monlib_support_nucleus_distances(monlib, resnames)
|
|
153
|
+
logger.writeln("adjusting hydrogen position to nucleus")
|
|
154
|
+
topo.adjust_hydrogen_distances(gemmi.Restraints.DistanceOf.Nucleus, default_scale=1.1)
|
|
155
|
+
elif h_pos == "elec" and make.get("hydr") == "y" and not no_adjust_hydrogen_distances:
|
|
156
|
+
logger.writeln("adjusting hydrogen position to electron cloud")
|
|
157
|
+
topo.adjust_hydrogen_distances(gemmi.Restraints.DistanceOf.ElectronCloud)
|
|
158
|
+
|
|
159
|
+
if fix_long_resnames: refmac_fixes.fix_long_resnames(st)
|
|
160
|
+
|
|
161
|
+
# remove "given" ncs matrices
|
|
162
|
+
# TODO write them back to the output files
|
|
163
|
+
st.ncs = gemmi.NcsOpList(x for x in st.ncs if not x.given)
|
|
164
|
+
|
|
165
|
+
# for safety
|
|
166
|
+
if "_entry.id" in st.info:
|
|
167
|
+
st.info["_entry.id"] = st.info["_entry.id"].replace(" ", "")
|
|
168
|
+
date_key = "_pdbx_database_status.recvd_initial_deposition_date"
|
|
169
|
+
if date_key in st.info:
|
|
170
|
+
tmp = st.info[date_key]
|
|
171
|
+
if len(tmp) > 5 and tmp[4] == "-":
|
|
172
|
+
if len(tmp) > 8 and tmp[8] != "" and not tmp[5:7].isdigit():
|
|
173
|
+
tmp = "XX"
|
|
174
|
+
elif len(tmp) > 6 and tmp[5] == "-":
|
|
175
|
+
if not tmp[3:5].isdigit():
|
|
176
|
+
tmp = "XX"
|
|
177
|
+
st.info[date_key] = tmp
|
|
178
|
+
# internal chain ID
|
|
179
|
+
for chain in st[0]:
|
|
180
|
+
for res in chain:
|
|
181
|
+
if len(chain.name) < 3:
|
|
182
|
+
# Change Axp (or AAxp) to A_p (or AA_p)
|
|
183
|
+
res.subchain = chain.name + "_" + res.subchain[len(chain.name)+1:]
|
|
184
|
+
else:
|
|
185
|
+
# Refmac only expects '_' at 2nd or 3rd position, and can accept up to 4 letters.
|
|
186
|
+
# Using raw chain ID may change alignment result for local NCS restraints,
|
|
187
|
+
# but to avoid this we would need chain ID translation, which is too complicated.
|
|
188
|
+
# This also invalidates _struct_asym, which Refmac does not seem to care
|
|
189
|
+
res.subchain = chain.name
|
|
190
|
+
# change st.name if needed
|
|
191
|
+
block_names = utils.restraints.dictionary_block_names(monlib, topo)
|
|
192
|
+
for i in range(1000):
|
|
193
|
+
if st.name.lower() in block_names:
|
|
194
|
+
st.name = st.name + str(i)
|
|
195
|
+
doc = gemmi.prepare_refmac_crd(st, topo, monlib, h_change)
|
|
196
|
+
doc.write_file(crdout, options=gemmi.cif.Style.NoBlankLines)
|
|
197
|
+
logger.writeln("crd file written: {}".format(crdout))
|
|
198
|
+
return refmac_fixes, [x+"\n" for x in metal_kws]
|
|
199
|
+
# prepare_crd()
|
|
200
|
+
|
|
201
|
+
def get_output_model_names(xyzout):
|
|
202
|
+
# ref: WRITE_ATOMS_REFMAC in oppro_allocate.f
|
|
203
|
+
if xyzout is None: xyzout = "XYZOUT"
|
|
204
|
+
pdb, mmcif = "", ""
|
|
205
|
+
if len(xyzout) > 3:
|
|
206
|
+
if xyzout.lower().endswith("pdb"):
|
|
207
|
+
mmcif = xyzout[:-4] + ".mmcif"
|
|
208
|
+
pdb = xyzout
|
|
209
|
+
else:
|
|
210
|
+
if xyzout.lower().endswith("cif") and len(xyzout) > 5:
|
|
211
|
+
if xyzout.lower().endswith("mmcif"):
|
|
212
|
+
mmcif = xyzout
|
|
213
|
+
pdb = xyzout[:-6] + ".pdb"
|
|
214
|
+
else:
|
|
215
|
+
mmcif = xyzout
|
|
216
|
+
pdb = xyzout[:-4] + ".pdb"
|
|
217
|
+
else:
|
|
218
|
+
mmcif = xyzout + ".mmcif"
|
|
219
|
+
pdb = xyzout
|
|
220
|
+
else:
|
|
221
|
+
mmcif = xyzout + ".mmcif"
|
|
222
|
+
pdb = xyzout
|
|
223
|
+
|
|
224
|
+
return pdb, mmcif
|
|
225
|
+
# get_output_model_names()
|
|
226
|
+
|
|
227
|
+
def modify_output(pdbout, cifout, fixes, hout, cispeps, software_items, modres, keep_original_output=False, tls_addu=False):
|
|
228
|
+
st = utils.fileio.read_structure(cifout)
|
|
229
|
+
st.cispeps = cispeps
|
|
230
|
+
if os.path.exists(pdbout):
|
|
231
|
+
st_pdb = gemmi.read_pdb(pdbout)
|
|
232
|
+
st.raw_remarks = st_pdb.raw_remarks
|
|
233
|
+
# Refmac only writes NCS matrices to pdb
|
|
234
|
+
st.ncs = st_pdb.ncs
|
|
235
|
+
if "_struct_ncs_oper.id" in st_pdb.info: # to write identity operator
|
|
236
|
+
st.info["_struct_ncs_oper.id"] = st_pdb.info["_struct_ncs_oper.id"]
|
|
237
|
+
if fixes is not None:
|
|
238
|
+
fixes.modify_back(st)
|
|
239
|
+
for con in st.connections:
|
|
240
|
+
if con.link_id == "disulf":
|
|
241
|
+
con.type = gemmi.ConnectionType.Disulf
|
|
242
|
+
# should we check metals and put MetalC?
|
|
243
|
+
|
|
244
|
+
# fix entity (Refmac seems to make DNA non-polymer; as seen in 1fix)
|
|
245
|
+
if not fixes or not fixes.res_labels:
|
|
246
|
+
utils.model.setup_entities(st, clear=True, overwrite_entity_type=True, force_subchain_names=True,
|
|
247
|
+
fix_sequences=True)
|
|
248
|
+
|
|
249
|
+
# assuming refmac won't write MODRES
|
|
250
|
+
st.mod_residues = modres
|
|
251
|
+
|
|
252
|
+
# add servalcat version
|
|
253
|
+
if len(st.meta.software) > 0 and st.meta.software[-1].name == "refmac":
|
|
254
|
+
st.meta.software[-1].version += f" (refmacat {servalcat.__version__})"
|
|
255
|
+
st.meta.software = software_items + st.meta.software
|
|
256
|
+
|
|
257
|
+
suffix = ".org"
|
|
258
|
+
os.rename(cifout, cifout + suffix)
|
|
259
|
+
utils.fileio.write_mmcif(st, cifout, cifout + suffix)
|
|
260
|
+
|
|
261
|
+
if tls_addu:
|
|
262
|
+
doc_ref = gemmi.cif.read(cifout + suffix)
|
|
263
|
+
tls_groups = {int(x.id): x for x in st.meta.refinement[0].tls_groups}
|
|
264
|
+
tls_details = doc_ref[0].find_value("_ccp4_refine_tls.details")
|
|
265
|
+
if tls_groups and gemmi.cif.as_string(tls_details) == "U values: residual only":
|
|
266
|
+
st2 = st.clone()
|
|
267
|
+
for cra in st2[0].all():
|
|
268
|
+
tlsgr = tls_groups.get(cra.atom.tls_group_id)
|
|
269
|
+
if cra.atom.tls_group_id > 0 and tlsgr is not None:
|
|
270
|
+
if not cra.atom.aniso.nonzero():
|
|
271
|
+
u = cra.atom.b_iso * utils.model.b_to_u
|
|
272
|
+
cra.atom.aniso = gemmi.SMat33f(u, u, u, 0, 0, 0)
|
|
273
|
+
u_from_tls = gemmi.calculate_u_from_tls(tlsgr, cra.atom.pos)
|
|
274
|
+
cra.atom.aniso += gemmi.SMat33f(*u_from_tls.elements_pdb())
|
|
275
|
+
cra.atom.b_iso = cra.atom.aniso.trace() / 3. * utils.model.u_to_b
|
|
276
|
+
cifout2 = cifout[:cifout.rindex(".")] + "_addu" + cifout[cifout.rindex("."):]
|
|
277
|
+
doc_ref[0].set_pair("_ccp4_refine_tls.details", gemmi.cif.quote("U values: with tls added"))
|
|
278
|
+
utils.fileio.write_mmcif(st2, cifout2, cif_ref_doc=doc_ref)
|
|
279
|
+
else:
|
|
280
|
+
if not tls_groups:
|
|
281
|
+
msg = "TLS group definition not found in the model"
|
|
282
|
+
else:
|
|
283
|
+
msg = "TLS already applied to the U values"
|
|
284
|
+
logger.writeln(f"Error: --tls_addu requested, but {msg}.")
|
|
285
|
+
|
|
286
|
+
if st.has_d_fraction:
|
|
287
|
+
st.store_deuterium_as_fraction(False) # also useful for pdb
|
|
288
|
+
logger.writeln("will write a H/D expanded mmcif file")
|
|
289
|
+
cifout2 = cifout[:cifout.rindex(".")] + "_hd_expand" + cifout[cifout.rindex("."):]
|
|
290
|
+
utils.fileio.write_mmcif(st, cifout2, cifout + suffix)
|
|
291
|
+
|
|
292
|
+
chain_id_len_max = max([len(x) for x in utils.model.all_chain_ids(st)])
|
|
293
|
+
seqnums = [res.seqid.num for chain in st[0] for res in chain]
|
|
294
|
+
if chain_id_len_max > 1 or min(seqnums) <= -1000 or max(seqnums) >= 10000:
|
|
295
|
+
logger.writeln("This structure cannot be saved as an official PDB format. Using hybrid-36. Header part may be inaccurate.")
|
|
296
|
+
if not hout:
|
|
297
|
+
st.remove_hydrogens() # remove hydrogen from pdb, while kept in mmcif
|
|
298
|
+
os.rename(pdbout, pdbout + suffix)
|
|
299
|
+
utils.fileio.write_pdb(st, pdbout)
|
|
300
|
+
if not keep_original_output:
|
|
301
|
+
os.remove(pdbout + suffix)
|
|
302
|
+
os.remove(cifout + suffix)
|
|
303
|
+
# modify_output()
|
|
304
|
+
|
|
305
|
+
def main(args):
|
|
306
|
+
if len(args.opts) % 2 != 0: raise SystemExit("Invalid number of args")
|
|
307
|
+
args.ligand = sum(args.ligand, []) if args.ligand else []
|
|
308
|
+
|
|
309
|
+
inputs, keywords = read_stdin(sys.stdin) # TODO read psrestin also?
|
|
310
|
+
if not keywords["make"].get("exit"):
|
|
311
|
+
refmac_ver = utils.refmac.check_version(args.exe)
|
|
312
|
+
if not refmac_ver:
|
|
313
|
+
raise SystemExit("Error: Check Refmac installation or use --exe to give the location.")
|
|
314
|
+
if refmac_ver < (5, 8, 404):
|
|
315
|
+
raise SystemExit("Error: this version of Refmac is not supported. Update to 5.8.404 or newer")
|
|
316
|
+
|
|
317
|
+
opts = OrderedDict((args.opts[2*i].lower(), args.opts[2*i+1]) for i in range(len(args.opts)//2))
|
|
318
|
+
xyzin = opts.get("xyzin")
|
|
319
|
+
xyzout = opts.get("xyzout")
|
|
320
|
+
libin = opts.pop("libin", None)
|
|
321
|
+
if libin: args.ligand.append(libin)
|
|
322
|
+
if not args.monlib:
|
|
323
|
+
# if --monlib is given, it has priority.
|
|
324
|
+
args.monlib = opts.pop("clibd_mon", None)
|
|
325
|
+
for k in ("temp1", "scrref"): # scrref has priority
|
|
326
|
+
if k in opts:
|
|
327
|
+
logger.writeln("updating CCP4_SCR from {}={}".format(k, opts[k]))
|
|
328
|
+
os.environ["CCP4_SCR"] = os.path.dirname(opts[k]) # XXX "." may be given, which causes problem (os.path.isdir("") is False)
|
|
329
|
+
utils.refmac.ensure_ccp4scr()
|
|
330
|
+
if args.prefix:
|
|
331
|
+
if "xyzin" in opts and "xyzout" not in opts: opts["xyzout"] = args.prefix + ".pdb"
|
|
332
|
+
if "hklin" in opts and "hklout" not in opts: opts["hklout"] = args.prefix + ".mtz"
|
|
333
|
+
if "tlsin" in opts and "tlsout" not in opts: opts["tlsout"] = args.prefix + ".tls"
|
|
334
|
+
|
|
335
|
+
# TODO what if restin is given or make cr prepared is given?
|
|
336
|
+
# TODO check make pept/link/suga/ss/conn/symm/chain
|
|
337
|
+
|
|
338
|
+
if "hklin" in opts: # for history
|
|
339
|
+
software_items = utils.fileio.software_items_from_mtz(opts["hklin"])
|
|
340
|
+
else:
|
|
341
|
+
software_items = []
|
|
342
|
+
|
|
343
|
+
# Process model
|
|
344
|
+
crdout = None
|
|
345
|
+
refmac_fixes = None
|
|
346
|
+
cispeps = []
|
|
347
|
+
unre = keywords["refi"].get("type") == "unre"
|
|
348
|
+
if xyzin is not None:
|
|
349
|
+
#tmpfd, crdout = tempfile.mkstemp(prefix="gemmi_", suffix=".crd") # TODO use dir=CCP4_SCR
|
|
350
|
+
#os.close(tmpfd)
|
|
351
|
+
st = utils.fileio.read_structure(xyzin)
|
|
352
|
+
if not st.cell.is_crystal() and not unre:
|
|
353
|
+
if args.auto_box_with_padding is not None:
|
|
354
|
+
st.cell = utils.model.box_from_model(st[0], args.auto_box_with_padding)
|
|
355
|
+
st.spacegroup_hm = "P 1"
|
|
356
|
+
logger.writeln("Box size from the model with padding of {}: {}".format(args.auto_box_with_padding, st.cell.parameters))
|
|
357
|
+
else:
|
|
358
|
+
raise SystemExit("Error: unit cell is not defined in the model.")
|
|
359
|
+
xyzout_dir = os.path.dirname(get_output_model_names(opts.get("xyzout"))[0])
|
|
360
|
+
crdout = os.path.join(xyzout_dir,
|
|
361
|
+
"gemmi_{}_{}.crd".format(utils.fileio.splitext(os.path.basename(xyzin))[0], os.getpid()))
|
|
362
|
+
refmac_fixes, metal_kws = prepare_crd(st, crdout, args.ligand, make=keywords["make"], monlib_path=args.monlib,
|
|
363
|
+
h_pos="nucl" if keywords.get("source")=="ne" else "elec",
|
|
364
|
+
no_adjust_hydrogen_distances=args.no_adjust_hydrogen_distances,
|
|
365
|
+
keep_entities=args.keep_entities,
|
|
366
|
+
unre=unre)
|
|
367
|
+
inputs = metal_kws + inputs # add metal exte first; otherwise it may be affected by user-defined inputs
|
|
368
|
+
opts["xyzin"] = crdout
|
|
369
|
+
cispeps = st.cispeps
|
|
370
|
+
|
|
371
|
+
if keywords["make"].get("exit"):
|
|
372
|
+
return
|
|
373
|
+
|
|
374
|
+
# Run Refmac
|
|
375
|
+
cmd = [args.exe] + list(sum(tuple(opts.items()), ()))
|
|
376
|
+
env = os.environ
|
|
377
|
+
logger.writeln("Running REFMAC5..")
|
|
378
|
+
if args.monlib:
|
|
379
|
+
logger.writeln("CLIBD_MON={}".format(args.monlib))
|
|
380
|
+
env["CLIBD_MON"] = os.path.join(args.monlib, "") # should end with /
|
|
381
|
+
logger.writeln(" ".join(cmd))
|
|
382
|
+
p = subprocess.Popen(cmd, shell=False, stdin=subprocess.PIPE,
|
|
383
|
+
stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
|
|
384
|
+
universal_newlines=True, env=env)
|
|
385
|
+
if crdout: p.stdin.write("make cr prepared\n")
|
|
386
|
+
p.stdin.write("".join(inputs))
|
|
387
|
+
p.stdin.close()
|
|
388
|
+
# prepare conversion for long residue names
|
|
389
|
+
resn_conv = {}
|
|
390
|
+
if refmac_fixes:
|
|
391
|
+
for old, new in refmac_fixes.resn_old_new:
|
|
392
|
+
n = "{:4s}".format(old)
|
|
393
|
+
if len(n) > 4: n += " "
|
|
394
|
+
resn_conv[new] = n
|
|
395
|
+
# print raw output
|
|
396
|
+
for l in iter(p.stdout.readline, ""):
|
|
397
|
+
for tn in resn_conv:
|
|
398
|
+
l = l.replace(tn, resn_conv[tn])
|
|
399
|
+
logger.write(l)
|
|
400
|
+
retcode = p.wait()
|
|
401
|
+
logger.writeln("\nRefmac finished with exit code= {}".format(retcode))
|
|
402
|
+
|
|
403
|
+
if not args.keep_original_output and crdout and os.path.exists(crdout):
|
|
404
|
+
os.remove(crdout)
|
|
405
|
+
|
|
406
|
+
# Modify output
|
|
407
|
+
if xyzin is not None:
|
|
408
|
+
pdbout, cifout = get_output_model_names(opts.get("xyzout"))
|
|
409
|
+
if os.path.exists(cifout):
|
|
410
|
+
modify_output(pdbout, cifout, refmac_fixes, keywords["make"].get("hout"), cispeps,
|
|
411
|
+
software_items, st.mod_residues, args.keep_original_output, args.tls_addu)
|
|
412
|
+
# main()
|
|
413
|
+
|
|
414
|
+
def command_line():
|
|
415
|
+
import sys
|
|
416
|
+
args = parse_args(sys.argv[1:])
|
|
417
|
+
if args.prefix:
|
|
418
|
+
logger.set_file(args.prefix + ".log")
|
|
419
|
+
logger.write_header(command="refmacat")
|
|
420
|
+
main(args)
|
|
421
|
+
|
|
422
|
+
if __name__ == "__main__":
|
|
423
|
+
command_line()
|
|
File without changes
|