servalcat 0.4.60__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.

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