servalcat 0.4.99__cp39-cp39-macosx_10_14_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.

Potentially problematic release.


This version of servalcat might be problematic. Click here for more details.

Files changed (45) hide show
  1. servalcat/__init__.py +10 -0
  2. servalcat/__main__.py +120 -0
  3. servalcat/ext.cpython-39-darwin.so +0 -0
  4. servalcat/refine/__init__.py +0 -0
  5. servalcat/refine/cgsolve.py +100 -0
  6. servalcat/refine/refine.py +906 -0
  7. servalcat/refine/refine_geom.py +233 -0
  8. servalcat/refine/refine_spa.py +366 -0
  9. servalcat/refine/refine_xtal.py +281 -0
  10. servalcat/refine/spa.py +144 -0
  11. servalcat/refine/xtal.py +276 -0
  12. servalcat/refmac/__init__.py +0 -0
  13. servalcat/refmac/exte.py +182 -0
  14. servalcat/refmac/refmac_keywords.py +639 -0
  15. servalcat/refmac/refmac_wrapper.py +395 -0
  16. servalcat/spa/__init__.py +0 -0
  17. servalcat/spa/fofc.py +479 -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 +977 -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 +1547 -0
  27. servalcat/utils/fileio.py +744 -0
  28. servalcat/utils/generate_operators.py +296 -0
  29. servalcat/utils/hkl.py +714 -0
  30. servalcat/utils/logger.py +140 -0
  31. servalcat/utils/maps.py +345 -0
  32. servalcat/utils/model.py +782 -0
  33. servalcat/utils/refmac.py +760 -0
  34. servalcat/utils/restraints.py +781 -0
  35. servalcat/utils/symmetry.py +295 -0
  36. servalcat/xtal/__init__.py +0 -0
  37. servalcat/xtal/french_wilson.py +258 -0
  38. servalcat/xtal/run_refmac_small.py +240 -0
  39. servalcat/xtal/sigmaa.py +1644 -0
  40. servalcat/xtal/twin.py +121 -0
  41. servalcat-0.4.99.dist-info/METADATA +55 -0
  42. servalcat-0.4.99.dist-info/RECORD +45 -0
  43. servalcat-0.4.99.dist-info/WHEEL +5 -0
  44. servalcat-0.4.99.dist-info/entry_points.txt +4 -0
  45. servalcat-0.4.99.dist-info/licenses/LICENSE +373 -0
@@ -0,0 +1,233 @@
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 argparse
10
+ import os
11
+ import gemmi
12
+ import numpy
13
+ import json
14
+ import servalcat # for version
15
+ from servalcat.utils import logger
16
+ from servalcat import utils
17
+ from servalcat.refine.refine import Geom, Refine, convert_stats_to_dicts, update_meta, print_h_options
18
+ from servalcat.refmac import refmac_keywords
19
+
20
+ def add_arguments(parser):
21
+ group = parser.add_mutually_exclusive_group(required=True)
22
+ group.add_argument('--model',
23
+ help='Input atomic model file')
24
+ group.add_argument('--update_dictionary',
25
+ help="Dictionary file to be updated")
26
+ parser.add_argument("--monlib",
27
+ help="Monomer library path. Default: $CLIBD_MON")
28
+ parser.add_argument('--ligand', nargs="*", action="append",
29
+ help="restraint dictionary cif file(s)")
30
+ parser.add_argument('--ncycle', type=int, default=10,
31
+ help="number of CG cycles (default: %(default)d)")
32
+ parser.add_argument('--hydrogen', default="all", choices=["all", "yes", "no"],
33
+ help="all: add riding hydrogen atoms, yes: use hydrogen atoms if present, no: remove hydrogen atoms in input. "
34
+ "Default: %(default)s")
35
+ parser.add_argument('--find_links', action='store_true',
36
+ help='Automatically add links')
37
+ parser.add_argument('--randomize', type=float, default=0,
38
+ help='Shake coordinates with specified rmsd')
39
+ parser.add_argument('--ncsr', action='store_true',
40
+ help='Use local NCS restraints')
41
+ parser.add_argument('--keywords', nargs='+', action="append",
42
+ help="refmac keyword(s)")
43
+ parser.add_argument('--keyword_file', nargs='+', action="append",
44
+ help="refmac keyword file(s)")
45
+ parser.add_argument('-o','--output_prefix',
46
+ help="Output prefix")
47
+ parser.add_argument("--write_trajectory", action='store_true',
48
+ help="Write all output from cycles")
49
+
50
+ # add_arguments()
51
+
52
+ def parse_args(arg_list):
53
+ parser = argparse.ArgumentParser()
54
+ add_arguments(parser)
55
+ return parser.parse_args(arg_list)
56
+ # parse_args()
57
+
58
+ def add_program_info_to_dictionary(block, comp_id, program_name="servalcat", descriptor="optimization tool"):
59
+ # old acedrg used _pdbx_chem_comp_description_generator. and descriptor
60
+ # new acedrg (>280?) uses _acedrg_chem_comp_descriptor. and type
61
+ for tag, name in (("_acedrg_chem_comp_descriptor.", "type"),
62
+ ("_pdbx_chem_comp_description_generator.", "descriptor")):
63
+ tab = block.find(tag, ["program_name", "program_version", name])
64
+ if tab:
65
+ loop = tab.loop
66
+ # just overwrite version if it's there
67
+ for row in tab:
68
+ if row.str(0) == program_name and row.str(2) == descriptor:
69
+ row[1] = gemmi.cif.quote(servalcat.__version__)
70
+ return
71
+ break
72
+ else:
73
+ # it may be strange to say _acedrg in this case..
74
+ name = "type"
75
+ loop = block.init_loop("_acedrg_chem_comp_descriptor.", ["comp_id",
76
+ "program_name",
77
+ "program_version",
78
+ name])
79
+ tags = [x[x.index(".")+1:] for x in loop.tags]
80
+ row = ["" for _ in range(len(tags))]
81
+ for tag, val in (("comp_id", comp_id),
82
+ ("program_name", program_name),
83
+ ("program_version", servalcat.__version__),
84
+ (name, descriptor)):
85
+ if tag in tags: row[tags.index(tag)] = val
86
+ loop.add_row(gemmi.cif.quote_list(row))
87
+ # add_program_info_to_dictionary()
88
+
89
+ def refine_and_update_dictionary(cif_in, monomer_dir, output_prefix, randomize=0, ncycle1=10, ncycle2=30):
90
+ doc = gemmi.cif.read(cif_in)
91
+ for block in doc: # this block will be reused below
92
+ st = gemmi.make_structure_from_chemcomp_block(block)
93
+ if len(st) > 0: break
94
+ else:
95
+ raise SystemExit("No model in the cif file")
96
+ for i in range(len(st)-1):
97
+ del st[1]
98
+ try:
99
+ monlib = utils.restraints.load_monomer_library(st, monomer_dir=monomer_dir, # monlib is needed for ener_lib
100
+ cif_files=[cif_in],
101
+ stop_for_unknowns=True)
102
+ except RuntimeError as e:
103
+ raise SystemExit("Error: {}".format(e))
104
+ all_stats = []
105
+ for i_macro in 0, 1:
106
+ try:
107
+ topo, _ = utils.restraints.prepare_topology(st, monlib, h_change=[gemmi.HydrogenChange.Remove, gemmi.HydrogenChange.ReAdd][i_macro],
108
+ check_hydrogen=(i_macro == 1))
109
+ except RuntimeError as e:
110
+ raise SystemExit("Error: {}".format(e))
111
+
112
+ geom = Geom(st, topo, monlib, shake_rms=randomize)
113
+ refiner = Refine(st, geom)
114
+ logger.writeln("Running {} cycles with wchir=4 wvdw=2 {} hydrogen".format(ncycle1, ["without","with"][i_macro]))
115
+ geom.calc_kwds["wchir"] = 4
116
+ geom.calc_kwds["wvdw"] = 2
117
+ all_stats.append(refiner.run_cycles(ncycle1))
118
+
119
+ logger.writeln("Running {} cycles with wchir=1 wvdw=2 {} hydrogen".format(ncycle2, ["without","with"][i_macro]))
120
+ geom.calc_kwds["wchir"] = 1
121
+ geom.calc_kwds["wvdw"] = 2
122
+ all_stats.append(refiner.run_cycles(ncycle2))
123
+
124
+ # replace xyz
125
+ pos = {cra.atom.name: cra.atom.pos.tolist() for cra in refiner.st[0].all()}
126
+ for row in block.find("_chem_comp_atom.", ["atom_id", "?x", "?y", "?z",
127
+ "?pdbx_model_Cartn_x_ideal",
128
+ "?pdbx_model_Cartn_y_ideal",
129
+ "?pdbx_model_Cartn_z_ideal",
130
+ "?model_Cartn_x", "?model_Cartn_y", "?model_Cartn_z"]):
131
+ p = pos[row.str(0)]
132
+ for i in range(3):
133
+ if row.has(i+1):
134
+ row[i+1] = "{:.3f}".format(p[i])
135
+ if row.has(i+4):
136
+ row[i+4] = "{:.3f}".format(p[i])
137
+ if row.has(i+7):
138
+ row[i+7] = "{:.3f}".format(p[i])
139
+ # add description
140
+ add_program_info_to_dictionary(block, st[0][0][0].name)
141
+ doc.write_file(output_prefix + "_updated.cif", options=gemmi.cif.Style.Aligned)
142
+ logger.writeln("Updated dictionary saved: {}".format(output_prefix + "_updated.cif"))
143
+ with open(output_prefix + "_stats.json", "w") as ofs:
144
+ json.dump([convert_stats_to_dicts(x) for x in all_stats],
145
+ ofs, indent=2)
146
+ logger.writeln("Refinement statistics saved: {}".format(ofs.name))
147
+ # refine_and_update_dictionary()
148
+
149
+ def refine_geom(model_in, monomer_dir, cif_files, h_change, ncycle, output_prefix, randomize, params,
150
+ find_links=False, use_ncsr=False):
151
+ st = utils.fileio.read_structure(model_in)
152
+ utils.model.setup_entities(st, clear=True, force_subchain_names=True, overwrite_entity_type=True)
153
+ if not all(op.given for op in st.ncs):
154
+ st2 = st.clone()
155
+ logger.writeln("Take NCS constraints into account.")
156
+ st2.expand_ncs(gemmi.HowToNameCopiedChain.Dup, merge_dist=0)
157
+ utils.fileio.write_model(st2, file_name="input_expanded.pdb")
158
+ try:
159
+ monlib = utils.restraints.load_monomer_library(st, monomer_dir=monomer_dir,
160
+ cif_files=cif_files,
161
+ stop_for_unknowns=True,
162
+ params=params)
163
+ except RuntimeError as e:
164
+ raise SystemExit("Error: {}".format(e))
165
+ utils.restraints.find_and_fix_links(st, monlib, find_metal_links=find_links,
166
+ add_found=find_links) # should remove unknown id here?
167
+ try:
168
+ topo, _ = utils.restraints.prepare_topology(st, monlib, h_change=h_change,
169
+ check_hydrogen=(h_change==gemmi.HydrogenChange.NoChange),
170
+ params=params)
171
+ except RuntimeError as e:
172
+ raise SystemExit("Error: {}".format(e))
173
+
174
+ print_h_options(h_change, st[0].has_hydrogen(), refine_h=True, hout=True, geom_only=True)
175
+
176
+ if use_ncsr:
177
+ ncslist = utils.restraints.prepare_ncs_restraints(st)
178
+ else:
179
+ ncslist = False
180
+ geom = Geom(st, topo, monlib, shake_rms=randomize, params=params, ncslist=ncslist)
181
+ refiner = Refine(st, geom, params=params)
182
+ stats = refiner.run_cycles(ncycle,
183
+ stats_json_out=output_prefix + "_stats.json")
184
+ update_meta(st, stats[-1])
185
+ refiner.st.name = output_prefix
186
+ utils.fileio.write_model(refiner.st, output_prefix, pdb=True, cif=True)
187
+ if params["write_trajectory"]:
188
+ utils.fileio.write_model(refiner.st_traj, output_prefix + "_traj", cif=True)
189
+ # refine_geom()
190
+
191
+ def main(args):
192
+ keywords = []
193
+ if args.keywords: keywords = sum(args.keywords, [])
194
+ if args.keyword_file: keywords.extend(l for f in sum(args.keyword_file, []) for l in open(f))
195
+ decide_prefix = lambda f: utils.fileio.splitext(os.path.basename(f))[0] + "_refined"
196
+ if args.model:
197
+ params = refmac_keywords.parse_keywords(keywords)
198
+ params["write_trajectory"] = args.write_trajectory
199
+ if not args.output_prefix:
200
+ args.output_prefix = decide_prefix(args.model)
201
+ if args.ligand:
202
+ args.ligand = sum(args.ligand, [])
203
+ h_change = {"all":gemmi.HydrogenChange.ReAddButWater,
204
+ "full":gemmi.HydrogenChange.ReAdd,
205
+ "yes":gemmi.HydrogenChange.NoChange,
206
+ "no":gemmi.HydrogenChange.Remove}[args.hydrogen]
207
+ refine_geom(model_in=args.model,
208
+ monomer_dir=args.monlib,
209
+ cif_files=args.ligand,
210
+ h_change=h_change,
211
+ ncycle=args.ncycle,
212
+ output_prefix=args.output_prefix,
213
+ randomize=args.randomize,
214
+ params=params,
215
+ find_links=args.find_links,
216
+ use_ncsr=args.ncsr)
217
+ else:
218
+ if not args.output_prefix:
219
+ args.output_prefix = decide_prefix(args.update_dictionary)
220
+ if args.ligand:
221
+ logger.writeln("WARNING: monlib and ligand are ignored in the dictionary updating mode")
222
+ if keywords:
223
+ logger.writeln("WARNING: refmac keywords are ignored in the dictionary updating mode")
224
+ refine_and_update_dictionary(cif_in=args.update_dictionary,
225
+ monomer_dir=args.monlib,
226
+ output_prefix=args.output_prefix,
227
+ randomize=args.randomize)
228
+ # main()
229
+
230
+ if __name__ == "__main__":
231
+ import sys
232
+ args = parse_args(sys.argv[1:])
233
+ main(args)
@@ -0,0 +1,366 @@
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 argparse
11
+ import numpy
12
+ from servalcat.utils import logger
13
+ from servalcat import utils
14
+ from servalcat.spa.run_refmac import check_args, process_input, calc_fsc, calc_fofc
15
+ from servalcat.spa import fofc
16
+ from servalcat.refine import spa
17
+ from servalcat.refine.refine import Geom, Refine, update_meta, print_h_options
18
+ from servalcat.refmac import refmac_keywords
19
+ b_to_u = utils.model.b_to_u
20
+
21
+ def add_arguments(parser):
22
+ parser.description = "program to refine cryo-EM SPA structures"
23
+ group = parser.add_mutually_exclusive_group(required=True)
24
+ group.add_argument("--halfmaps", nargs=2, help="Input half map files")
25
+ group.add_argument("--map", help="Use this only if you really do not have half maps.")
26
+ group.add_argument("--hklin", help="Use mtz file. With limited functionality.")
27
+ parser.add_argument('--pixel_size', type=float,
28
+ help='Override pixel size (A)')
29
+ parser.add_argument('--labin',
30
+ help='F,PHI for hklin')
31
+ parser.add_argument('--model', required=True,
32
+ help='Input atomic model file')
33
+ parser.add_argument("-d", '--resolution', type=float, required=True)
34
+ parser.add_argument('-r', '--mask_radius', type=float, default=3, help="mask radius")
35
+ parser.add_argument('--padding',
36
+ type=float,
37
+ help='Default: 2*mask_radius')
38
+ parser.add_argument('--no_mask', action='store_true')
39
+ parser.add_argument('--no_trim',
40
+ action='store_true',
41
+ help='Keep original box (not recommended)')
42
+ parser.add_argument('--mask_soft_edge',
43
+ type=float, default=0,
44
+ help='Add soft edge to model mask. Should use with --no_sharpen_before_mask?')
45
+ parser.add_argument('--no_sharpen_before_mask', action='store_true',
46
+ help='By default half maps are sharpened before masking by std of signal and unsharpened after masking. This option disables it.')
47
+ parser.add_argument("--b_before_mask", type=float,
48
+ help="sharpening B value for sharpen-mask-unsharpen procedure. By default it is determined automatically.")
49
+ parser.add_argument('--blur',
50
+ type=float, default=0,
51
+ help='Sharpening or blurring B')
52
+ parser.add_argument("--monlib",
53
+ help="Monomer library path. Default: $CLIBD_MON")
54
+ parser.add_argument('--ligand', nargs="*", action="append",
55
+ help="restraint dictionary cif file(s)")
56
+ parser.add_argument('--newligand_continue', action='store_true',
57
+ help="Make ad-hoc restraints for unknown ligands (not recommended)")
58
+ parser.add_argument('--hydrogen', default="all", choices=["all", "yes", "no"],
59
+ help="all: (re)generate hydrogen atoms, yes: use hydrogen atoms if present, no: remove hydrogen atoms in input. "
60
+ "Default: %(default)s")
61
+ parser.add_argument('--hout', action='store_true', help="write hydrogen atoms in the output model")
62
+ parser.add_argument('--jellybody', action='store_true',
63
+ help="Use jelly body restraints")
64
+ parser.add_argument('--jellybody_params', nargs=2, type=float,
65
+ metavar=("sigma", "dmax"), default=[0.01, 4.2],
66
+ help="Jelly body sigma and dmax (default: %(default)s)")
67
+ parser.add_argument('--jellyonly', action='store_true',
68
+ help="Jelly body only (experimental, may not be useful)")
69
+ utils.symmetry.add_symmetry_args(parser) # add --pg etc
70
+ parser.add_argument('--contacting_only', action="store_true", help="Filter out non-contacting strict NCS copies")
71
+ parser.add_argument('--ignore_symmetry', action='store_true',
72
+ help='Ignore symmetry information (MTRIX/_struct_ncs_oper) in the model file')
73
+ parser.add_argument('--find_links', action='store_true',
74
+ help='Automatically add links')
75
+ parser.add_argument('--no_check_ncs_overlaps', action='store_true',
76
+ help='Disable model overlap test due to strict NCS')
77
+ parser.add_argument('--no_check_ncs_map', action='store_true',
78
+ help='Disable map symmetry test due to strict NCS')
79
+ parser.add_argument('--no_check_mask_with_model', action='store_true',
80
+ help='Disable mask test using model')
81
+ parser.add_argument('--keywords', nargs='+', action="append",
82
+ help="refmac keyword(s)")
83
+ parser.add_argument('--keyword_file', nargs='+', action="append",
84
+ help="refmac keyword file(s)")
85
+ parser.add_argument('--randomize', type=float, default=0,
86
+ help='Shake coordinates with the specified rmsd value')
87
+ parser.add_argument('--ncycle', type=int, default=10,
88
+ help="number of CG cycles (default: %(default)d)")
89
+ parser.add_argument('--weight', type=float,
90
+ help="refinement weight. default: automatic")
91
+ parser.add_argument('--no_weight_adjust', action='store_true',
92
+ help='Do not adjust weight during refinement')
93
+ parser.add_argument('--target_bond_rmsz_range', nargs=2, type=float, default=[0.5, 1.],
94
+ help='Bond rmsz range for weight adjustment (default: %(default)s)')
95
+ parser.add_argument('--adpr_weight', type=float, default=1.,
96
+ help="ADP restraint weight (default: %(default)f)")
97
+ parser.add_argument('--occr_weight', type=float, default=1.,
98
+ help="Occupancy restraint weight (default: %(default)f)")
99
+ parser.add_argument('--ncsr', action='store_true',
100
+ help='Use local NCS restraints')
101
+ parser.add_argument('--bfactor', type=float,
102
+ help="reset all atomic B values to the specified value")
103
+ parser.add_argument('--fix_xyz', action="store_true",
104
+ help="Fix atomic coordinates")
105
+ parser.add_argument('--adp', choices=["fix", "iso", "aniso"], default="iso",
106
+ help="ADP parameterization")
107
+ parser.add_argument('--refine_all_occ', action="store_true")
108
+ parser.add_argument('--max_dist_for_adp_restraint', type=float, default=4.)
109
+ parser.add_argument('--adp_restraint_power', type=float)
110
+ parser.add_argument('--adp_restraint_exp_fac', type=float)
111
+ parser.add_argument('--adp_restraint_no_long_range', action='store_true')
112
+ parser.add_argument('--adp_restraint_mode', choices=["diff", "kldiv"], default="diff")
113
+ parser.add_argument('--unrestrained', action='store_true', help="No positional restraints")
114
+ parser.add_argument('--refine_h', action="store_true", help="Refine hydrogen against data (default: only restraints apply)")
115
+ parser.add_argument("-s", "--source", choices=["electron", "xray", "neutron"], default="electron")
116
+ parser.add_argument('-o','--output_prefix', default="refined")
117
+ parser.add_argument('--cross_validation', action='store_true',
118
+ help='Run cross validation. Only "throughout" mode is available (no "shake" mode)')
119
+ group = parser.add_mutually_exclusive_group()
120
+ group.add_argument('--mask_for_fofc', help="Mask file for Fo-Fc map calculation")
121
+ group.add_argument('--mask_radius_for_fofc', type=float, help="Mask radius for Fo-Fc map calculation")
122
+ parser.add_argument("--fsc_resolution", type=float,
123
+ help="High resolution limit for FSC calculation. Default: Nyquist")
124
+ parser.add_argument('--keep_charges', action='store_true',
125
+ help="Use scattering factor for charged atoms. Use it with care.")
126
+ parser.add_argument("--keep_entities", action='store_true',
127
+ help="Do not override entities")
128
+ parser.add_argument("--write_trajectory", action='store_true',
129
+ help="Write all output from cycles")
130
+ # add_arguments()
131
+
132
+ def parse_args(arg_list):
133
+ parser = argparse.ArgumentParser()
134
+ add_arguments(parser)
135
+ return parser.parse_args(arg_list)
136
+ # parse_args()
137
+
138
+ def main(args):
139
+ args.mask = None
140
+ args.invert_mask = False
141
+ args.trim_fofc_mtz = args.mask_for_fofc is not None
142
+ args.cross_validation_method = "throughout"
143
+ check_args(args)
144
+ params = refmac_keywords.parse_keywords(args.keywords + [l for f in args.keyword_file for l in open(f)])
145
+ params["write_trajectory"] = args.write_trajectory
146
+
147
+ st = utils.fileio.read_structure(args.model)
148
+ if args.unrestrained:
149
+ monlib = gemmi.MonLib()
150
+ topo = None
151
+ if args.hydrogen == "all":
152
+ logger.writeln("\nWARNING: in unrestrained refinement hydrogen atoms are not generated.\n")
153
+ args.hydrogen = "yes"
154
+ elif args.hydrogen == "no":
155
+ st.remove_hydrogens()
156
+ for i, cra in enumerate(st[0].all()):
157
+ cra.atom.serial = i + 1
158
+ else:
159
+ try:
160
+ monlib = utils.restraints.load_monomer_library(st, monomer_dir=args.monlib, cif_files=args.ligand,
161
+ stop_for_unknowns=not args.newligand_continue,
162
+ params=params)
163
+ except RuntimeError as e:
164
+ raise SystemExit("Error: {}".format(e))
165
+ if not args.keep_entities:
166
+ utils.model.setup_entities(st, clear=True, force_subchain_names=True, overwrite_entity_type=True)
167
+ if not args.keep_charges:
168
+ utils.model.remove_charge([st])
169
+ utils.model.check_atomsf([st], args.source)
170
+ if args.hklin:
171
+ assert not args.cross_validation
172
+ mtz = utils.fileio.read_mmhkl(args.hklin)
173
+ hkldata = utils.hkl.hkldata_from_mtz(mtz, args.labin.split(","),
174
+ newlabels=["FP", ""],
175
+ require_types=["F", "P"])
176
+ hkldata.df = hkldata.df.dropna() # workaround for missing data
177
+ #hkldata.setup_relion_binning()
178
+ hkldata.setup_binning(n_bins=10) # need to sort out
179
+ st.cell = hkldata.cell
180
+ st.spacegroup_hm = hkldata.sg.xhm()
181
+ st.setup_cell_images()
182
+ info = {}
183
+ utils.restraints.find_and_fix_links(st, monlib, find_metal_links=args.find_links,
184
+ add_found=args.find_links)
185
+ else:
186
+ if args.halfmaps:
187
+ maps = utils.fileio.read_halfmaps(args.halfmaps, pixel_size=args.pixel_size)
188
+ else:
189
+ maps = [utils.fileio.read_ccp4_map(args.map, pixel_size=args.pixel_size)]
190
+ hkldata, info = process_input(st, maps, resolution=args.resolution - 1e-6, monlib=monlib,
191
+ mask_in=args.mask, args=args, use_refmac=False,
192
+ find_links=args.find_links)
193
+ h_change = {"all":gemmi.HydrogenChange.ReAddKnown,
194
+ "yes":gemmi.HydrogenChange.NoChange,
195
+ "no":gemmi.HydrogenChange.Remove}[args.hydrogen]
196
+ try:
197
+ topo, _ = utils.restraints.prepare_topology(st, monlib, h_change=h_change,
198
+ check_hydrogen=(args.hydrogen=="yes"),
199
+ params=params)
200
+ except RuntimeError as e:
201
+ raise SystemExit("Error: {}".format(e))
202
+
203
+ print_h_options(h_change, st[0].has_hydrogen(), args.refine_h, args.hout, geom_only=False)
204
+
205
+ # initialize ADP
206
+ utils.model.reset_adp(st[0], args.bfactor, args.adp)
207
+
208
+ # auto weight
209
+ if args.weight is None:
210
+ # from 230303_weight_test using 472 test cases
211
+ reso = info["d_eff"] if "d_eff" in info else args.resolution
212
+ if "vol_ratio" in info:
213
+ if "d_eff" in info:
214
+ rlmc = (-2.3976, 0.5933, 3.5160)
215
+ else:
216
+ rlmc = (-2.5151, 0.6681, 3.6467)
217
+ logger.writeln("Estimating weight auto scale using resolution and volume ratio")
218
+ ws = numpy.exp(rlmc[0] + reso*rlmc[1] +info["vol_ratio"]*rlmc[2])
219
+ else:
220
+ if "d_eff" in info:
221
+ rlmc = (-1.6908, 0.5668)
222
+ else:
223
+ rlmc = (-1.7588, 0.6311)
224
+ logger.writeln("Estimating weight auto scale using resolution")
225
+ ws = numpy.exp(rlmc[0] + args.resolution*rlmc[1])
226
+ args.weight = max(0.2, min(18.0, ws))
227
+ logger.writeln(" Will use weight= {:.2f}".format(args.weight))
228
+
229
+ if args.ncsr:
230
+ ncslist = utils.restraints.prepare_ncs_restraints(st)
231
+ else:
232
+ ncslist = False
233
+ geom = Geom(st, topo, monlib, shake_rms=args.randomize, adpr_w=args.adpr_weight, occr_w=args.occr_weight,
234
+ params=params, unrestrained=args.unrestrained or args.jellyonly,
235
+ ncslist=ncslist)
236
+ ll = spa.LL_SPA(hkldata, st, monlib,
237
+ lab_obs="F_map1" if args.cross_validation else "FP",
238
+ source=args.source)
239
+ refiner = Refine(st, geom, ll,
240
+ refine_xyz=not args.fix_xyz,
241
+ adp_mode=dict(fix=0, iso=1, aniso=2)[args.adp],
242
+ refine_h=args.refine_h,
243
+ unrestrained=args.unrestrained,
244
+ params=params,
245
+ refine_occ=args.refine_all_occ)
246
+
247
+ geom.geom.adpr_max_dist = args.max_dist_for_adp_restraint
248
+ if args.adp_restraint_power is not None: geom.geom.adpr_d_power = args.adp_restraint_power
249
+ if args.adp_restraint_exp_fac is not None: geom.geom.adpr_exp_fac = args.adp_restraint_exp_fac
250
+ if args.adp_restraint_no_long_range: geom.geom.adpr_long_range = False
251
+ geom.geom.adpr_mode = args.adp_restraint_mode
252
+ if args.jellybody or args.jellyonly: geom.geom.ridge_sigma, geom.geom.ridge_dmax = args.jellybody_params
253
+ if args.jellyonly: geom.geom.ridge_exclude_short_dist = False
254
+
255
+ #logger.writeln("TEST: shift x+0.3 A")
256
+ #for cra in st[0].all():
257
+ # cra.atom.pos += gemmi.Position(0.3,0,0)
258
+
259
+ stats = refiner.run_cycles(args.ncycle, weight=args.weight,
260
+ weight_adjust=not args.no_weight_adjust,
261
+ weight_adjust_bond_rmsz_range=args.target_bond_rmsz_range,
262
+ stats_json_out=args.output_prefix + "_stats.json")
263
+ if not args.hklin and not args.no_trim:
264
+ refiner.st.cell = maps[0][0].unit_cell
265
+ refiner.st.setup_cell_images()
266
+
267
+ if params["write_trajectory"]:
268
+ utils.fileio.write_model(refiner.st_traj, args.output_prefix + "_traj", cif=True)
269
+
270
+ # Expand sym here
271
+ st_expanded = refiner.st.clone()
272
+ if not all(op.given for op in st.ncs):
273
+ utils.model.expand_ncs(st_expanded)
274
+ utils.fileio.write_model(st_expanded, args.output_prefix+"_expanded", pdb=True, cif=True, hout=args.hout)
275
+
276
+ # Calc FSC
277
+ if args.hklin: # cannot update a mask
278
+ stats_for_meta = stats[-1]
279
+ else:
280
+ mask = utils.fileio.read_ccp4_map(args.mask)[0] if args.mask else None
281
+ fscavg_text, stats2 = calc_fsc(st_expanded, args.output_prefix, maps,
282
+ args.resolution, mask=mask, mask_radius=args.mask_radius if not args.no_mask else None,
283
+ soft_edge=args.mask_soft_edge,
284
+ b_before_mask=args.b_before_mask,
285
+ no_sharpen_before_mask=args.no_sharpen_before_mask,
286
+ make_hydrogen="yes", # no change needed in the model
287
+ monlib=monlib,
288
+ blur=args.blur,
289
+ d_min_fsc=args.fsc_resolution,
290
+ cross_validation=args.cross_validation,
291
+ cross_validation_method=args.cross_validation_method
292
+ )
293
+ stats_for_meta = {"geom": stats[-1]["geom"], "data": stats2}
294
+ update_meta(refiner.st, stats_for_meta, ll)
295
+ refiner.st.name = args.output_prefix
296
+ utils.fileio.write_model(refiner.st, args.output_prefix, pdb=True, cif=True, hout=args.hout)
297
+ if args.hklin:
298
+ return
299
+ # Calc Fo-Fc (and updated) maps
300
+ diffmap_prefix = "{}_diffmap".format(args.output_prefix)
301
+ calc_fofc(refiner.st, st_expanded, maps, monlib, ".mmcif", args, diffmap_prefix=diffmap_prefix)
302
+
303
+ # Final summary
304
+ adpstats_txt = ""
305
+ adp_stats = utils.model.adp_stats_per_chain(refiner.st[0])
306
+ max_chain_len = max([len(x[0]) for x in adp_stats])
307
+ max_num_len = max([len(str(x[1])) for x in adp_stats])
308
+ for chain, natoms, qs in adp_stats:
309
+ adpstats_txt += " Chain {0:{1}s}".format(chain, max_chain_len) if chain!="*" else " {0:{1}s}".format("All", max_chain_len+6)
310
+ adpstats_txt += " ({0:{1}d} atoms) min={2:5.1f} median={3:5.1f} max={4:5.1f} A^2\n".format(natoms, max_num_len, qs[0],qs[2],qs[4])
311
+
312
+ if "geom" in stats[-1] and "Bond distances, non H" in stats[-1]["geom"]["summary"].index:
313
+ rmsbond = stats[-1]["geom"]["summary"]["r.m.s.d."]["Bond distances, non H"]
314
+ rmsangle = stats[-1]["geom"]["summary"]["r.m.s.d."]["Bond angles, non H"]
315
+ else:
316
+ rmsbond, rmsangle = numpy.nan, numpy.nan
317
+ if args.mask_for_fofc:
318
+ map_peaks_str = """\
319
+ List Fo-Fc map peaks in the ASU:
320
+ servalcat util map_peaks --map {diffmap_prefix}_normalized_fofc.mrc --model {prefix}.pdb --abs_level 4.0 \
321
+ """.format(prefix=args.output_prefix, diffmap_prefix=diffmap_prefix)
322
+ else:
323
+ map_peaks_str = "WARNING: --mask_for_fofc was not given, so the Fo-Fc map was not normalized."
324
+
325
+ logger.writeln("""
326
+ =============================================================================
327
+ * Final Summary *
328
+
329
+ Rmsd from ideal
330
+ bond lengths: {rmsbond:.4f} A
331
+ bond angles: {rmsangle:.3f} deg
332
+
333
+ {fscavgs}
334
+ Run loggraph {fsclog} to see plots
335
+
336
+ ADP statistics
337
+ {adpstats}
338
+
339
+ Weight used: {final_weight:.3e}
340
+ If you want to change the weight, give larger (looser restraints)
341
+ or smaller (tighter) value to --weight=.
342
+
343
+ Open refined model and {diffmap_prefix}.mtz with COOT:
344
+ coot --script {prefix}_coot.py
345
+
346
+ Open refined model, map and difference map with ChimeraX/ISOLDE:
347
+ chimerax {prefix}_chimerax.cxc
348
+
349
+ {map_peaks_msg}
350
+ =============================================================================
351
+ """.format(rmsbond=rmsbond,
352
+ rmsangle=rmsangle,
353
+ fscavgs=fscavg_text.rstrip(),
354
+ fsclog="{}_fsc.log".format(args.output_prefix),
355
+ adpstats=adpstats_txt.rstrip(),
356
+ final_weight=args.weight,
357
+ prefix=args.output_prefix,
358
+ diffmap_prefix=diffmap_prefix,
359
+ map_peaks_msg=map_peaks_str))
360
+
361
+ # main()
362
+
363
+ if __name__ == "__main__":
364
+ import sys
365
+ args = parse_args(sys.argv[1:])
366
+ main(args)