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
servalcat/spa/fofc.py
ADDED
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
# TODO shift map first using mask!
|
|
2
|
+
"""
|
|
3
|
+
Author: "Keitaro Yamashita, Garib N. Murshudov"
|
|
4
|
+
MRC Laboratory of Molecular Biology
|
|
5
|
+
|
|
6
|
+
This software is released under the
|
|
7
|
+
Mozilla Public License, version 2.0; see LICENSE.
|
|
8
|
+
"""
|
|
9
|
+
from __future__ import absolute_import, division, print_function, generators
|
|
10
|
+
import gemmi
|
|
11
|
+
import numpy
|
|
12
|
+
import time
|
|
13
|
+
from servalcat.utils import logger
|
|
14
|
+
from servalcat import utils
|
|
15
|
+
from servalcat.spa import shift_maps
|
|
16
|
+
import argparse
|
|
17
|
+
|
|
18
|
+
def add_arguments(parser):
|
|
19
|
+
parser.description = 'Fo-Fc map calculation based on model and data errors'
|
|
20
|
+
group = parser.add_mutually_exclusive_group()
|
|
21
|
+
group.add_argument("--halfmaps", nargs=2)
|
|
22
|
+
group.add_argument("--map", help="Use only if you really do not have half maps.")
|
|
23
|
+
parser.add_argument('--pixel_size', type=float,
|
|
24
|
+
help='Override pixel size (A)')
|
|
25
|
+
parser.add_argument('--model', required=True,
|
|
26
|
+
help='Input atomic model file')
|
|
27
|
+
parser.add_argument("-d", '--resolution', type=float, required=True)
|
|
28
|
+
parser.add_argument('-m', '--mask', help="mask file")
|
|
29
|
+
parser.add_argument('-r', '--mask_radius', type=float, help="mask radius (not used if --mask is given)")
|
|
30
|
+
parser.add_argument('--no_check_mask_with_model', action='store_true',
|
|
31
|
+
help='Disable mask test using model')
|
|
32
|
+
parser.add_argument("-B", type=float, help="Estimated blurring")
|
|
33
|
+
parser.add_argument("--half1_only", action='store_true', help="Only use half 1 for map calculation (use half 2 only for noise estimation)")
|
|
34
|
+
parser.add_argument("--normalized_map", action='store_true',
|
|
35
|
+
help="Write normalized map in the masked region. Now this is on by default.")
|
|
36
|
+
parser.add_argument("--no_fsc_weights", action='store_true',
|
|
37
|
+
help="Just for debugging purpose: turn off FSC-based weighting")
|
|
38
|
+
parser.add_argument("--sharpening_b", type=float,
|
|
39
|
+
help="Use B value (negative value for sharpening) instead of standard deviation of the signal")
|
|
40
|
+
parser.add_argument("--trim", action='store_true',
|
|
41
|
+
help="Write trimmed maps")
|
|
42
|
+
parser.add_argument("--trim_mtz", action='store_true',
|
|
43
|
+
help="Write trimmed mtz")
|
|
44
|
+
parser.add_argument("--monlib",
|
|
45
|
+
help="Monomer library path. Default: $CLIBD_MON")
|
|
46
|
+
parser.add_argument("--omit_proton", action='store_true',
|
|
47
|
+
#help="Omit hydrogen proton (leaving electrons) from model in map calculation")
|
|
48
|
+
help=argparse.SUPPRESS)
|
|
49
|
+
parser.add_argument("--omit_h_electron", action='store_true',
|
|
50
|
+
#help="Omit hydrogen electrons (leaving protons) from model in map calculation")
|
|
51
|
+
help=argparse.SUPPRESS)
|
|
52
|
+
parser.add_argument("-s", "--source", choices=["electron", "xray", "neutron", "custom"], default="electron")
|
|
53
|
+
parser.add_argument('-o','--output_prefix', default="diffmap",
|
|
54
|
+
help='output file name prefix (default: %(default)s)')
|
|
55
|
+
parser.add_argument('--keep_charges', action='store_true',
|
|
56
|
+
help="Use scattering factor for charged atoms. Use it with care.")
|
|
57
|
+
# add_arguments()
|
|
58
|
+
|
|
59
|
+
def parse_args(arg_list):
|
|
60
|
+
parser = argparse.ArgumentParser()
|
|
61
|
+
add_arguments(parser)
|
|
62
|
+
return parser.parse_args(arg_list)
|
|
63
|
+
# parse_args()
|
|
64
|
+
|
|
65
|
+
def calc_D_and_S(hkldata, has_halfmaps=True, half1_only=False):#fo_asu, fc_asu, varn, bins, bin_idxes):
|
|
66
|
+
bdf = hkldata.binned_df["ml"]
|
|
67
|
+
bdf["D"] = 0.
|
|
68
|
+
bdf["S"] = 0.
|
|
69
|
+
stats_str = """$TABLE: Statistics :
|
|
70
|
+
$GRAPHS
|
|
71
|
+
: log(Mn(|F|^2)) and variances :A:1,6,7,8,13,14:
|
|
72
|
+
: FSC :A:1,9,10,11:
|
|
73
|
+
: weights :A:1,12,15,16:
|
|
74
|
+
: map weights :A:1,17:
|
|
75
|
+
$$
|
|
76
|
+
1/resol^2 bin n d_max d_min log(var(Fo)) log(var(Fc)) log(var(DFc)) FSC.model FSC.full sqrt(FSC.full) D log(var_U,T) log(var_noise) wFo wFc wFo.sharpen
|
|
77
|
+
$$
|
|
78
|
+
$$
|
|
79
|
+
"""
|
|
80
|
+
tmpl = "{:.4f} {:3d} {:7d} {:7.3f} {:7.3f} {:.4e} {:.4e} {:4e} {: .4f} {: .4f} {: .4f} {: .4e} {:.4e} {:.4e} {:.4f} {:.4f} {:.4e}\n"
|
|
81
|
+
|
|
82
|
+
var_noise = None
|
|
83
|
+
FP = hkldata.df.FP.to_numpy()
|
|
84
|
+
if half1_only:
|
|
85
|
+
FP = hkldata.df.F_map1.to_numpy()
|
|
86
|
+
var_noise = hkldata.binned_df["ml"].var_noise * 2
|
|
87
|
+
elif has_halfmaps:
|
|
88
|
+
var_noise = hkldata.binned_df["ml"].var_noise
|
|
89
|
+
|
|
90
|
+
for i_bin, idxes in hkldata.binned("ml"):
|
|
91
|
+
bin_d_min = hkldata.binned_df["ml"].d_min[i_bin]
|
|
92
|
+
bin_d_max = hkldata.binned_df["ml"].d_max[i_bin]
|
|
93
|
+
Fo = FP[idxes]
|
|
94
|
+
Fc = hkldata.df.FC.to_numpy()[idxes]
|
|
95
|
+
fsc = numpy.real(numpy.corrcoef(Fo, Fc)[1,0])
|
|
96
|
+
bdf.loc[i_bin, "D"] = numpy.sum(numpy.real(Fo * numpy.conj(Fc)))/numpy.sum(numpy.abs(Fc)**2)
|
|
97
|
+
if has_halfmaps:
|
|
98
|
+
varn = var_noise[i_bin]
|
|
99
|
+
fsc_full = hkldata.binned_df["ml"].FSCfull[i_bin]
|
|
100
|
+
S = max(0, numpy.average(numpy.abs(Fo-bdf.D[i_bin]*Fc)**2)-varn)
|
|
101
|
+
bdf.loc[i_bin, "S"] = S
|
|
102
|
+
w = S/(S+varn)
|
|
103
|
+
if fsc_full < 0: # this should be fixed actually. needs smoothing to zero.
|
|
104
|
+
w_sharpen = 0
|
|
105
|
+
else:
|
|
106
|
+
w_sharpen = w / numpy.sqrt(fsc_full) / numpy.std(Fo)
|
|
107
|
+
else:
|
|
108
|
+
varn = fsc_full = 0
|
|
109
|
+
w = 1
|
|
110
|
+
w_sharpen = 1
|
|
111
|
+
|
|
112
|
+
with numpy.errstate(divide="ignore", invalid="ignore"):
|
|
113
|
+
stats_str += tmpl.format(1/bin_d_min**2, i_bin, Fo.size, bin_d_max, bin_d_min,
|
|
114
|
+
numpy.log(numpy.average(numpy.abs(Fo)**2)),
|
|
115
|
+
numpy.log(numpy.average(numpy.abs(Fc)**2)),
|
|
116
|
+
numpy.log(bdf.D[i_bin]**2*numpy.average(numpy.abs(Fc)**2)),
|
|
117
|
+
fsc, fsc_full, numpy.sqrt(fsc_full), bdf.D[i_bin],
|
|
118
|
+
numpy.log(bdf.S[i_bin]), numpy.log(varn),
|
|
119
|
+
w, 1-w, w_sharpen)
|
|
120
|
+
return stats_str
|
|
121
|
+
# calc_D_and_S()
|
|
122
|
+
|
|
123
|
+
#import line_profiler
|
|
124
|
+
#profile = line_profiler.LineProfiler()
|
|
125
|
+
#import atexit
|
|
126
|
+
#atexit.register(profile.print_stats)
|
|
127
|
+
#@profile
|
|
128
|
+
def calc_maps(hkldata, B=None, has_halfmaps=True, half1_only=False, no_fsc_weights=False, sharpening_b=None):
|
|
129
|
+
has_fc = "FC" in hkldata.df
|
|
130
|
+
|
|
131
|
+
if not has_fc:
|
|
132
|
+
labs = ["FWT"]
|
|
133
|
+
if B is not None: labs.append("FWT_b0")
|
|
134
|
+
elif has_halfmaps:
|
|
135
|
+
labs = ["Fupdate", "DELFWT", "FWT", "DELFWT_noscale", "Fupdate_noscale"]
|
|
136
|
+
if B is not None: labs.extend(["Fupdate_b0", "DELFWT_b0", "FWT_b0"])
|
|
137
|
+
else:
|
|
138
|
+
labs = ["DELFWT"]
|
|
139
|
+
|
|
140
|
+
tmp = {}
|
|
141
|
+
for l in labs:
|
|
142
|
+
tmp[l] = numpy.zeros(len(hkldata.df.index), numpy.complex128)
|
|
143
|
+
|
|
144
|
+
logger.writeln("Calculating maps..")
|
|
145
|
+
logger.write(" sharpening method: ")
|
|
146
|
+
if sharpening_b is None:
|
|
147
|
+
logger.writeln("1/sqrt(FSC * Mn(Fo)) for Fo and 1/sigma_U,T for Fo-Fc")
|
|
148
|
+
else:
|
|
149
|
+
logger.writeln("1/exp(-B*s^2/4) with B= {:.2f}".format(sharpening_b))
|
|
150
|
+
|
|
151
|
+
time_t = time.time()
|
|
152
|
+
|
|
153
|
+
if half1_only:
|
|
154
|
+
FP = hkldata.df.F_map1.to_numpy()
|
|
155
|
+
else:
|
|
156
|
+
FP = hkldata.df.FP.to_numpy()
|
|
157
|
+
|
|
158
|
+
s2 = 1./hkldata.d_spacings().to_numpy()**2
|
|
159
|
+
|
|
160
|
+
fsc_became_negative = False
|
|
161
|
+
|
|
162
|
+
for i_bin, idxes in hkldata.binned("ml"):
|
|
163
|
+
if has_halfmaps:
|
|
164
|
+
fsc = hkldata.binned_df["ml"].FSCfull[i_bin] # FSCfull
|
|
165
|
+
if half1_only:
|
|
166
|
+
varn = hkldata.binned_df["ml"].var_noise[i_bin] * 2
|
|
167
|
+
fsc = fsc/(2-fsc) # to FSChalf
|
|
168
|
+
else:
|
|
169
|
+
varn = hkldata.binned_df["ml"].var_noise[i_bin]
|
|
170
|
+
else:
|
|
171
|
+
fsc, varn = 1., 0.
|
|
172
|
+
|
|
173
|
+
w_nomodel = 1. if no_fsc_weights else fsc
|
|
174
|
+
Fo = FP[idxes]
|
|
175
|
+
sig_fo = numpy.std(Fo)
|
|
176
|
+
s2_bin = s2[idxes]
|
|
177
|
+
|
|
178
|
+
if has_fc:
|
|
179
|
+
Fc = hkldata.df.FC.to_numpy()[idxes]
|
|
180
|
+
D = hkldata.binned_df["ml"].D[i_bin]
|
|
181
|
+
S = hkldata.binned_df["ml"].S[i_bin] # variance of unexplained signal
|
|
182
|
+
w = 1. if no_fsc_weights or not has_halfmaps else S/(S+varn)
|
|
183
|
+
delfwt = w * (Fo-D*Fc)
|
|
184
|
+
fup = 2 * w * Fo + (1 - 2*w) * D*Fc # <F> + delfwt
|
|
185
|
+
if has_halfmaps: # no point making this map when half maps not given
|
|
186
|
+
tmp["DELFWT_noscale"][idxes] = delfwt
|
|
187
|
+
tmp["Fupdate_noscale"][idxes] = fup
|
|
188
|
+
|
|
189
|
+
if not fsc_became_negative and fsc <= 0:
|
|
190
|
+
logger.writeln(" WARNING: cutting resolution at {:.2f} A because fsc < 0".format(hkldata.binned_df["ml"].d_max[i_bin]))
|
|
191
|
+
fsc_became_negative = True
|
|
192
|
+
if fsc_became_negative:
|
|
193
|
+
continue
|
|
194
|
+
|
|
195
|
+
if sharpening_b is None:
|
|
196
|
+
k = sig_fo * numpy.sqrt(fsc)
|
|
197
|
+
k_fofc = numpy.sqrt(S) if has_fc and S > 0 else 1. # to avoid zero-division. if S=0 then w=0.
|
|
198
|
+
else:
|
|
199
|
+
k = k_fofc = numpy.exp(-sharpening_b*s2_bin/4)
|
|
200
|
+
|
|
201
|
+
lab_suf = "" if B is None else "_b0"
|
|
202
|
+
if has_halfmaps:
|
|
203
|
+
tmp["FWT"+lab_suf][idxes] = w_nomodel / k * Fo
|
|
204
|
+
if has_fc:
|
|
205
|
+
tmp["DELFWT"+lab_suf][idxes] = delfwt / k_fofc
|
|
206
|
+
tmp["Fupdate"+lab_suf][idxes] = fup / k
|
|
207
|
+
elif has_fc:
|
|
208
|
+
tmp["DELFWT"+lab_suf][idxes] = delfwt
|
|
209
|
+
|
|
210
|
+
if B is not None and has_halfmaps: # local B based map
|
|
211
|
+
k_l = numpy.exp(-B*s2_bin/4.)
|
|
212
|
+
k2_l = numpy.exp(-B*s2_bin/2.)
|
|
213
|
+
fsc_l = k2_l*fsc/(1+(k2_l-1)*fsc)
|
|
214
|
+
w_nomodel = 1. if no_fsc_weights else fsc_l
|
|
215
|
+
tmp["FWT"][idxes] = Fo*w_nomodel/k/k_l
|
|
216
|
+
if has_fc:
|
|
217
|
+
S_l = S * k2_l
|
|
218
|
+
w = 1. if no_fsc_weights or not has_halfmaps else S_l/(S_l+varn)
|
|
219
|
+
delfwt = (Fo-D*Fc)*w/k_fofc/k_l
|
|
220
|
+
fup = (w*Fo+(1.-w)*D*Fc)/k/k_l
|
|
221
|
+
logger.writeln("{:4d} {:.4e} {:.4e} {:.4e} {:.4e} {:.4e} {:.4e}".format(i_bin,
|
|
222
|
+
numpy.average(k),
|
|
223
|
+
numpy.average(sig_fo),
|
|
224
|
+
numpy.average(fsc_l),
|
|
225
|
+
numpy.average(k_l),
|
|
226
|
+
numpy.average(abs(fup)),
|
|
227
|
+
numpy.average(abs(delfwt))))
|
|
228
|
+
tmp["DELFWT"][idxes] = delfwt
|
|
229
|
+
tmp["Fupdate"][idxes] = fup
|
|
230
|
+
|
|
231
|
+
for l in labs:
|
|
232
|
+
hkldata.df[l] = tmp[l]
|
|
233
|
+
|
|
234
|
+
logger.writeln(" finished in {:.3f} sec.".format(time.time()-time_t))
|
|
235
|
+
return labs
|
|
236
|
+
# calc_maps()
|
|
237
|
+
|
|
238
|
+
def dump_to_mtz(hkldata, map_labs, mtz_out):
|
|
239
|
+
extra_labs = list(filter(lambda x: x in hkldata.df, ["FP", "FC"]))
|
|
240
|
+
map_labs = map_labs + extra_labs
|
|
241
|
+
hkldata.write_mtz(mtz_out, map_labs)
|
|
242
|
+
# dump_to_mtz()
|
|
243
|
+
|
|
244
|
+
def calc_fofc(st, d_min, maps, mask=None, monlib=None, B=None, half1_only=False,
|
|
245
|
+
no_fsc_weights=False, sharpening_b=None, omit_proton=False, omit_h_electron=False,
|
|
246
|
+
source="electron"):
|
|
247
|
+
if no_fsc_weights:
|
|
248
|
+
logger.writeln("WARNING: --no_fsc_weights is requested.")
|
|
249
|
+
if sharpening_b is not None:
|
|
250
|
+
logger.writeln("WARNING: --sharpening_b={} is given".format(sharpening_b))
|
|
251
|
+
|
|
252
|
+
hkldata = utils.maps.mask_and_fft_maps(maps, d_min, mask)
|
|
253
|
+
hkldata.df["FC"] = utils.model.calc_fc_fft(st, d_min - 1e-6, monlib=monlib, source=source,
|
|
254
|
+
miller_array=hkldata.miller_array())
|
|
255
|
+
if mask is not None:
|
|
256
|
+
fc_map = hkldata.fft_map("FC", grid_size=mask.shape)
|
|
257
|
+
fc_map.array[:] *= mask
|
|
258
|
+
hkldata.df["FC"] = gemmi.transform_map_to_f_phi(fc_map).get_value_by_hkl(hkldata.miller_array())
|
|
259
|
+
|
|
260
|
+
hkldata.setup_relion_binning("ml")
|
|
261
|
+
|
|
262
|
+
has_halfmaps = (len(maps) == 2)
|
|
263
|
+
if has_halfmaps:
|
|
264
|
+
utils.maps.calc_noise_var_from_halfmaps(hkldata)
|
|
265
|
+
|
|
266
|
+
stats_str = calc_D_and_S(hkldata, has_halfmaps=has_halfmaps, half1_only=half1_only)
|
|
267
|
+
|
|
268
|
+
if omit_proton or omit_h_electron:
|
|
269
|
+
hkldata.df["FC"] = utils.model.calc_fc_fft(st, d_min - 1e-6, monlib=monlib, source=source,
|
|
270
|
+
omit_proton=omit_proton, omit_h_electron=omit_h_electron,
|
|
271
|
+
miller_array=hkldata.miller_array())
|
|
272
|
+
|
|
273
|
+
map_labs = calc_maps(hkldata, B=B, has_halfmaps=has_halfmaps, half1_only=half1_only,
|
|
274
|
+
no_fsc_weights=no_fsc_weights, sharpening_b=sharpening_b)
|
|
275
|
+
return hkldata, map_labs, stats_str
|
|
276
|
+
# calc_fofc()
|
|
277
|
+
|
|
278
|
+
def write_files(hkldata, map_labs, grid_start, stats_str,
|
|
279
|
+
mask=None, output_prefix="diffmap", trim_map=False, trim_mtz=False,
|
|
280
|
+
normalize_map=True, omit_h_electron=False):
|
|
281
|
+
# this function may modify the overall scale of FWT/DELFWT.
|
|
282
|
+
|
|
283
|
+
if mask is not None and (trim_map or trim_mtz):
|
|
284
|
+
new_cell, new_shape, new_grid_start, shifts = shift_maps.determine_shape_and_shift(mask=gemmi.FloatGrid(mask.array,
|
|
285
|
+
hkldata.cell,
|
|
286
|
+
hkldata.sg),
|
|
287
|
+
grid_start=grid_start,
|
|
288
|
+
padding=5,
|
|
289
|
+
mask_cutoff=0.5,
|
|
290
|
+
noncentered=True,
|
|
291
|
+
noncubic=True,
|
|
292
|
+
json_out=None)
|
|
293
|
+
else:
|
|
294
|
+
new_cell, new_shape, new_grid_start, shifts = None, None, None, None
|
|
295
|
+
|
|
296
|
+
if trim_map:
|
|
297
|
+
grid_start_for_map = new_grid_start
|
|
298
|
+
shape_for_map = new_shape
|
|
299
|
+
else:
|
|
300
|
+
grid_start_for_map = grid_start
|
|
301
|
+
shape_for_map = None
|
|
302
|
+
|
|
303
|
+
if normalize_map and mask is not None:
|
|
304
|
+
cutoff = 0.5
|
|
305
|
+
if "DELFWT" in hkldata.df:
|
|
306
|
+
logger.writeln("Normalized Fo-Fc map requested.")
|
|
307
|
+
delfwt_map = hkldata.fft_map("DELFWT", grid_size=mask.shape)
|
|
308
|
+
masked = delfwt_map.array[mask.array>cutoff]
|
|
309
|
+
logger.writeln(" Whole volume: {} voxels".format(delfwt_map.point_count))
|
|
310
|
+
logger.writeln(" Masked volume: {} voxels (>{})".format(masked.size, cutoff))
|
|
311
|
+
global_mean = numpy.average(delfwt_map)
|
|
312
|
+
global_std = numpy.std(delfwt_map)
|
|
313
|
+
logger.writeln(" Global mean: {:.3e}".format(global_mean))
|
|
314
|
+
logger.writeln(" Global std: {:.3e}".format(global_std))
|
|
315
|
+
masked_mean = numpy.average(masked)
|
|
316
|
+
masked_std = numpy.std(masked)
|
|
317
|
+
logger.writeln(" Masked mean: {:.3e}".format(masked_mean))
|
|
318
|
+
logger.writeln(" Masked std: {:.3e}".format(masked_std))
|
|
319
|
+
#logger.writeln(" If you want to scale manually: {}".format())
|
|
320
|
+
scaled = (delfwt_map - masked_mean)/masked_std
|
|
321
|
+
hkldata.df["DELFWT"] /= masked_std # it would work if masked_mean~0
|
|
322
|
+
if omit_h_electron:
|
|
323
|
+
scaled *= -1
|
|
324
|
+
filename = "{}_normalized_fofc_flipsign.mrc".format(output_prefix)
|
|
325
|
+
else:
|
|
326
|
+
filename = "{}_normalized_fofc.mrc".format(output_prefix)
|
|
327
|
+
logger.writeln(" Writing {}".format(filename))
|
|
328
|
+
utils.maps.write_ccp4_map(filename, scaled, cell=hkldata.cell,
|
|
329
|
+
grid_start=grid_start_for_map, grid_shape=shape_for_map)
|
|
330
|
+
|
|
331
|
+
# Write Fo map as well
|
|
332
|
+
if "FWT" in hkldata.df:
|
|
333
|
+
fwt_map = hkldata.fft_map("FWT", grid_size=mask.shape)
|
|
334
|
+
masked = fwt_map.array[mask.array>cutoff]
|
|
335
|
+
masked_mean = numpy.average(masked)
|
|
336
|
+
masked_std = numpy.std(masked)
|
|
337
|
+
scaled = (fwt_map - masked_mean)/masked_std # does not make much sense for Fo map though
|
|
338
|
+
hkldata.df["FWT"] /= masked_std # it would work if masked_mean~0
|
|
339
|
+
filename = "{}_normalized_fo.mrc".format(output_prefix)
|
|
340
|
+
logger.writeln(" Writing {}".format(filename))
|
|
341
|
+
utils.maps.write_ccp4_map(filename, scaled, cell=hkldata.cell,
|
|
342
|
+
grid_start=grid_start_for_map, grid_shape=shape_for_map)
|
|
343
|
+
|
|
344
|
+
if trim_mtz and shifts is not None:
|
|
345
|
+
hkldata2 = utils.hkl.HklData(new_cell, hkldata.sg, df=None)
|
|
346
|
+
d_min = hkldata.d_min_max()[0]
|
|
347
|
+
for lab in map_labs + ["FP", "FC"]:
|
|
348
|
+
if lab not in hkldata.df: continue
|
|
349
|
+
gr = hkldata.fft_map(lab, grid_size=mask.shape)
|
|
350
|
+
gr = gemmi.FloatGrid(gr.get_subarray(new_grid_start, new_shape),
|
|
351
|
+
new_cell, hkldata.sg)
|
|
352
|
+
if hkldata2.df is None:
|
|
353
|
+
ad = gemmi.transform_map_to_f_phi(gr).prepare_asu_data(dmin=d_min)
|
|
354
|
+
hkldata2.merge_asu_data(ad, lab)
|
|
355
|
+
else:
|
|
356
|
+
hkldata2.df[lab] = gemmi.transform_map_to_f_phi(gr).get_value_by_hkl(hkldata2.miller_array())
|
|
357
|
+
hkldata2.translate(lab, -shifts)
|
|
358
|
+
hkldata = hkldata2
|
|
359
|
+
|
|
360
|
+
dump_to_mtz(hkldata, map_labs, "{}_maps.mtz".format(output_prefix))
|
|
361
|
+
if stats_str:
|
|
362
|
+
with open("{}_Fstats.log".format(output_prefix), "w") as f:
|
|
363
|
+
f.write(stats_str)
|
|
364
|
+
# write_files()
|
|
365
|
+
|
|
366
|
+
def write_coot_script(py_out, model_file, mtz_file, contour_fo=1.2, contour_fofc=3.0, ncs_ops=None):
|
|
367
|
+
with open(py_out, "w") as ofs:
|
|
368
|
+
ofs.write('imol = read_pdb("{}")\n'.format(model_file)) # TODO safer
|
|
369
|
+
ofs.write('imol_fo = make_and_draw_map("{}", "FWT", "PHWT", "", 0, 0)\n'.format(mtz_file))
|
|
370
|
+
ofs.write('imol_fofc = make_and_draw_map("{}", "DELFWT", "PHDELWT", "", 0, 1)\n'.format(mtz_file))
|
|
371
|
+
if contour_fo is not None:
|
|
372
|
+
ofs.write('set_contour_level_absolute(imol_fo, {:.1f})\n'.format(contour_fo))
|
|
373
|
+
if contour_fofc is not None:
|
|
374
|
+
ofs.write('set_contour_level_absolute(imol_fofc, {:.1f})\n'.format(contour_fofc))
|
|
375
|
+
if ncs_ops is not None:
|
|
376
|
+
for op in ncs_ops:
|
|
377
|
+
if op.given: continue
|
|
378
|
+
c, resid = utils.symmetry.find_center_of_origin(op.tr.mat, op.tr.vec)
|
|
379
|
+
if resid.length() > 1e-6: continue # coot does not support translation..
|
|
380
|
+
v = [y for x in op.tr.mat.tolist() for y in x] + c.tolist()
|
|
381
|
+
ofs.write("add_molecular_symmetry(imol, {})\n".format(",".join(str(x) for x in v)))
|
|
382
|
+
# write_coot_script()
|
|
383
|
+
|
|
384
|
+
def write_chimerax_script(cxc_out, model_file, fo_mrc_file, fofc_mrc_file):
|
|
385
|
+
with open(cxc_out, "w") as ofs:
|
|
386
|
+
ofs.write('open {}\n'.format(model_file))
|
|
387
|
+
ofs.write('open {}\n'.format(fo_mrc_file))
|
|
388
|
+
ofs.write('open {}\n'.format(fofc_mrc_file))
|
|
389
|
+
ofs.write('volume #3 level 4 level -4 color #00FF00 color #FF0000 squaremesh false cap false style mesh meshlighting false\n')
|
|
390
|
+
ofs.write('isolde start\n')
|
|
391
|
+
ofs.write('clipper associate #2 toModel #1\n')
|
|
392
|
+
ofs.write('clipper associate #3 toModel #1\n')
|
|
393
|
+
# write_chimerax_script()
|
|
394
|
+
|
|
395
|
+
def main(args):
|
|
396
|
+
if not args.halfmaps and not args.map:
|
|
397
|
+
raise SystemExit("Error: give --halfmaps or --map")
|
|
398
|
+
|
|
399
|
+
if not args.halfmaps and args.B is not None:
|
|
400
|
+
raise SystemExit("Error: -B only works with half maps")
|
|
401
|
+
|
|
402
|
+
if args.half1_only:
|
|
403
|
+
if not args.halfmaps:
|
|
404
|
+
raise SystemExit("--half1_only requires half maps")
|
|
405
|
+
logger.error("--half1_only specified. Half map 2 is used only for noise estimation")
|
|
406
|
+
|
|
407
|
+
if args.normalized_map:
|
|
408
|
+
logger.writeln("DeprecationWarning: --normalized_map is now on by default. This option will be removed in the future.")
|
|
409
|
+
|
|
410
|
+
if not args.halfmaps:
|
|
411
|
+
logger.error("Warning: using --halfmaps is strongly recommended!")
|
|
412
|
+
|
|
413
|
+
st = utils.fileio.read_structure(args.model)
|
|
414
|
+
ccu = utils.model.CustomCoefUtil()
|
|
415
|
+
if not args.keep_charges:
|
|
416
|
+
utils.model.remove_charge([st])
|
|
417
|
+
if args.source == "custom":
|
|
418
|
+
ccu.read_from_cif(st, args.model)
|
|
419
|
+
ccu.show_info()
|
|
420
|
+
ccu.set_coeffs(st)
|
|
421
|
+
else:
|
|
422
|
+
utils.model.check_atomsf([st], args.source)
|
|
423
|
+
ncs_org = gemmi.NcsOpList(st.ncs)
|
|
424
|
+
utils.model.expand_ncs(st)
|
|
425
|
+
|
|
426
|
+
if (args.omit_proton or args.omit_h_electron) and not st[0].has_hydrogen():
|
|
427
|
+
raise SystemExit("ERROR! --omit_proton/--omit_h_electron requested, but no hydrogen atoms were found.")
|
|
428
|
+
|
|
429
|
+
if args.halfmaps:
|
|
430
|
+
maps = utils.fileio.read_halfmaps(args.halfmaps, pixel_size=args.pixel_size)
|
|
431
|
+
has_halfmaps = True
|
|
432
|
+
else:
|
|
433
|
+
maps = [utils.fileio.read_ccp4_map(args.map, pixel_size=args.pixel_size)]
|
|
434
|
+
has_halfmaps = False
|
|
435
|
+
|
|
436
|
+
grid_start = maps[0][1]
|
|
437
|
+
g = maps[0][0]
|
|
438
|
+
st.spacegroup_hm = "P1"
|
|
439
|
+
st.cell = g.unit_cell
|
|
440
|
+
|
|
441
|
+
if st[0].has_hydrogen():
|
|
442
|
+
monlib = utils.restraints.load_monomer_library(st, monomer_dir=args.monlib)
|
|
443
|
+
else:
|
|
444
|
+
monlib = None
|
|
445
|
+
|
|
446
|
+
if args.mask:
|
|
447
|
+
mask = utils.fileio.read_ccp4_map(args.mask)[0]
|
|
448
|
+
if not args.no_check_mask_with_model:
|
|
449
|
+
if not utils.maps.test_mask_with_model(mask, st):
|
|
450
|
+
raise SystemExit("\nError: Model is out of mask.\n"
|
|
451
|
+
"Please check your --model and --mask. You can disable this test with --no_check_mask_with_model.")
|
|
452
|
+
elif args.mask_radius:
|
|
453
|
+
mask = utils.maps.mask_from_model(st, args.mask_radius, grid=g)
|
|
454
|
+
utils.maps.write_ccp4_map("mask_from_model.ccp4", mask)
|
|
455
|
+
else:
|
|
456
|
+
mask = None
|
|
457
|
+
logger.writeln("Warning: Mask is needed for map normalization. Use --mask or --mask_radius if you want normalized map.")
|
|
458
|
+
|
|
459
|
+
hkldata, map_labs, stats_str = calc_fofc(st, args.resolution, maps, mask=mask, monlib=monlib, B=args.B,
|
|
460
|
+
half1_only=args.half1_only, no_fsc_weights=args.no_fsc_weights,
|
|
461
|
+
sharpening_b=args.sharpening_b, omit_proton=args.omit_proton,
|
|
462
|
+
omit_h_electron=args.omit_h_electron,
|
|
463
|
+
source=args.source)
|
|
464
|
+
write_files(hkldata, map_labs, grid_start, stats_str,
|
|
465
|
+
mask=mask, output_prefix=args.output_prefix,
|
|
466
|
+
trim_map=args.trim, trim_mtz=args.trim_mtz, omit_h_electron=args.omit_h_electron)
|
|
467
|
+
|
|
468
|
+
py_out = "{}_coot.py".format(args.output_prefix)
|
|
469
|
+
write_coot_script(py_out, model_file=args.model,
|
|
470
|
+
mtz_file=args.output_prefix+"_maps.mtz",
|
|
471
|
+
contour_fo=None if mask is None else 1.2,
|
|
472
|
+
contour_fofc=None if mask is None else 3.0,
|
|
473
|
+
ncs_ops=ncs_org)
|
|
474
|
+
logger.writeln("\nOpen model and diffmap mtz with COOT:")
|
|
475
|
+
logger.writeln("coot --script " + py_out)
|
|
476
|
+
if mask is not None:
|
|
477
|
+
logger.writeln("\nWant to list Fo-Fc map peaks? Try:")
|
|
478
|
+
if args.omit_h_electron:
|
|
479
|
+
logger.writeln("servalcat util map_peaks --map {}_normalized_fofc_flipsign.mrc --model {} --abs_level 4.0".format(args.output_prefix, args.model))
|
|
480
|
+
else:
|
|
481
|
+
logger.writeln("servalcat util map_peaks --map {}_normalized_fofc.mrc --model {} --abs_level 4.0".format(args.output_prefix, args.model))
|
|
482
|
+
|
|
483
|
+
# main()
|
|
484
|
+
|
|
485
|
+
if __name__ == "__main__":
|
|
486
|
+
import sys
|
|
487
|
+
args = parse_args(sys.argv[1:])
|
|
488
|
+
main(args)
|