servalcat 0.4.99__cp310-cp310-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-310-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,281 @@
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 pandas
12
+ import os
13
+ import shutil
14
+ import argparse
15
+ from servalcat.utils import logger
16
+ from servalcat import utils
17
+ from servalcat.xtal.sigmaa import decide_mtz_labels, process_input, calculate_maps, calculate_maps_int, calculate_maps_twin
18
+ from servalcat.refine.xtal import LL_Xtal
19
+ from servalcat.refine.refine import Geom, Refine, update_meta, print_h_options
20
+ from servalcat.refmac import refmac_keywords
21
+ from servalcat import ext
22
+ b_to_u = utils.model.b_to_u
23
+
24
+ def add_arguments(parser):
25
+ parser.description = "program to refine crystallographic structures"
26
+ parser.add_argument("--hklin", required=True)
27
+ parser.add_argument("-d", '--d_min', type=float)
28
+ parser.add_argument('--d_max', type=float)
29
+ parser.add_argument('--nbins', type=int,
30
+ help="Number of bins (default: auto)")
31
+ parser.add_argument("--labin", help="F,SIGF,FREE input")
32
+ parser.add_argument('--free', type=int,
33
+ help='flag number for test set')
34
+ parser.add_argument('--model', required=True,
35
+ help='Input atomic model file')
36
+ parser.add_argument("--monlib",
37
+ help="Monomer library path. Default: $CLIBD_MON")
38
+ parser.add_argument('--ligand', nargs="*", action="append",
39
+ help="restraint dictionary cif file(s)")
40
+ parser.add_argument('--newligand_continue', action='store_true',
41
+ help="Make ad-hoc restraints for unknown ligands (not recommended)")
42
+ parser.add_argument('--hydrogen', default="all", choices=["all", "yes", "no"],
43
+ help="all: add riding hydrogen atoms, yes: use hydrogen atoms if present, no: remove hydrogen atoms in input. "
44
+ "Default: %(default)s")
45
+ parser.add_argument('--hout', action='store_true', help="write hydrogen atoms in the output model")
46
+ parser.add_argument('--jellybody', action='store_true',
47
+ help="Use jelly body restraints")
48
+ parser.add_argument('--jellybody_params', nargs=2, type=float,
49
+ metavar=("sigma", "dmax"), default=[0.01, 4.2],
50
+ help="Jelly body sigma and dmax (default: %(default)s)")
51
+ parser.add_argument('--jellyonly', action='store_true',
52
+ help="Jelly body only (experimental, may not be useful)")
53
+ parser.add_argument('--find_links', action='store_true',
54
+ help='Automatically add links')
55
+ parser.add_argument('--keywords', nargs='+', action="append",
56
+ help="refmac keyword(s)")
57
+ parser.add_argument('--keyword_file', nargs='+', action="append",
58
+ help="refmac keyword file(s)")
59
+ parser.add_argument('--randomize', type=float, default=0,
60
+ help='Shake coordinates with specified rmsd')
61
+ parser.add_argument('--ncycle', type=int, default=10,
62
+ help="number of CG cycles (default: %(default)d)")
63
+ parser.add_argument('--weight', type=float,
64
+ help="refinement weight (default: auto)")
65
+ parser.add_argument('--no_weight_adjust', action='store_true',
66
+ help='Do not adjust weight during refinement')
67
+ parser.add_argument('--target_bond_rmsz_range', nargs=2, type=float, default=[0.5, 1.],
68
+ help='Bond rmsz range for weight adjustment (default: %(default)s)')
69
+ parser.add_argument('--ncsr', action='store_true',
70
+ help='Use local NCS restraints')
71
+ parser.add_argument('--adpr_weight', type=float, default=1.,
72
+ help="ADP restraint weight (default: %(default)f)")
73
+ parser.add_argument('--occr_weight', type=float, default=1.,
74
+ help="Occupancy restraint weight (default: %(default)f)")
75
+ parser.add_argument('--bfactor', type=float,
76
+ help="reset all atomic B values to specified value")
77
+ parser.add_argument('--fix_xyz', action="store_true")
78
+ parser.add_argument('--adp', choices=["fix", "iso", "aniso"], default="iso")
79
+ parser.add_argument('--refine_all_occ', action="store_true")
80
+ parser.add_argument('--max_dist_for_adp_restraint', type=float, default=4.)
81
+ parser.add_argument('--adp_restraint_power', type=float)
82
+ parser.add_argument('--adp_restraint_exp_fac', type=float)
83
+ parser.add_argument('--adp_restraint_no_long_range', action='store_true')
84
+ parser.add_argument('--adp_restraint_mode', choices=["diff", "kldiv"], default="kldiv")
85
+ parser.add_argument('--unrestrained', action='store_true', help="No positional restraints")
86
+ parser.add_argument('--refine_h', action="store_true", help="Refine hydrogen (default: restraints only)")
87
+ parser.add_argument('--twin', action="store_true", help="Turn on twin refinement")
88
+ parser.add_argument("-s", "--source", choices=["electron", "xray", "neutron"], required=True)
89
+ parser.add_argument('--no_solvent', action='store_true',
90
+ help="Do not consider bulk solvent contribution")
91
+ parser.add_argument('--use_work_in_est', action='store_true',
92
+ help="Use work reflections in ML parameter estimates")
93
+ parser.add_argument('--keep_charges', action='store_true',
94
+ help="Use scattering factor for charged atoms. Use it with care.")
95
+ parser.add_argument("--keep_entities", action='store_true',
96
+ help="Do not override entities")
97
+ parser.add_argument('--allow_unusual_occupancies', action="store_true", help="Allow negative or more than one occupancies")
98
+ parser.add_argument('-o','--output_prefix')
99
+ parser.add_argument("--write_trajectory", action='store_true',
100
+ help="Write all output from cycles")
101
+ parser.add_argument("--vonmises", action='store_true',
102
+ help="Experimental: von Mises type restraint for angles")
103
+ # add_arguments()
104
+
105
+ def parse_args(arg_list):
106
+ parser = argparse.ArgumentParser()
107
+ add_arguments(parser)
108
+ return parser.parse_args(arg_list)
109
+ # parse_args()
110
+
111
+ def main(args):
112
+ if args.source == "neutron": assert not args.refine_h # we need deuterium fraction handling in LL
113
+ if args.ligand: args.ligand = sum(args.ligand, [])
114
+ if not args.output_prefix:
115
+ args.output_prefix = utils.fileio.splitext(os.path.basename(args.model))[0] + "_refined"
116
+
117
+ keywords = []
118
+ if args.keywords or args.keyword_file:
119
+ if args.keywords: keywords = sum(args.keywords, [])
120
+ if args.keyword_file: keywords.extend(l for f in sum(args.keyword_file, []) for l in open(f))
121
+ params = refmac_keywords.parse_keywords(keywords)
122
+ params["write_trajectory"] = args.write_trajectory
123
+
124
+ hklin = args.hklin
125
+ labin = args.labin
126
+ if labin is not None:
127
+ labin = labin.split(",")
128
+ elif utils.fileio.is_mmhkl_file(hklin):
129
+ hklin = utils.fileio.read_mmhkl(hklin)
130
+ labin = decide_mtz_labels(hklin)
131
+
132
+ if labin and len(labin) == 3: # with test flags
133
+ use_in_target = "work"
134
+ if args.use_work_in_est:
135
+ use_in_est = "work"
136
+ n_per_bin = 100
137
+ else:
138
+ use_in_est = "test"
139
+ n_per_bin = 50
140
+ else:
141
+ use_in_est = "all"
142
+ use_in_target = "all"
143
+ n_per_bin = 100
144
+
145
+ try:
146
+ hkldata, sts, fc_labs, centric_and_selections, args.free = process_input(hklin=hklin,
147
+ labin=labin,
148
+ n_bins=args.nbins,
149
+ free=args.free,
150
+ xyzins=[args.model],
151
+ source=args.source,
152
+ d_max=args.d_max,
153
+ d_min=args.d_min,
154
+ n_per_bin=n_per_bin,
155
+ use=use_in_est,
156
+ max_bins=30,
157
+ keep_charges=args.keep_charges,
158
+ allow_unusual_occupancies=args.allow_unusual_occupancies)
159
+ except RuntimeError as e:
160
+ raise SystemExit("Error: {}".format(e))
161
+
162
+ is_int = "I" in hkldata.df
163
+ st = sts[0]
164
+ utils.model.fix_deuterium_residues(st)
165
+ if args.unrestrained:
166
+ monlib = gemmi.MonLib()
167
+ topo = None
168
+ h_change = gemmi.HydrogenChange.NoChange
169
+ if args.hydrogen == "all":
170
+ logger.writeln("\nWARNING: in unrestrained refinement hydrogen atoms are not generated.\n")
171
+ elif args.hydrogen == "no":
172
+ st.remove_hydrogens()
173
+ h_change = gemmi.HydrogenChange.Remove
174
+ for i, cra in enumerate(st[0].all()):
175
+ cra.atom.serial = i + 1
176
+ else:
177
+ try:
178
+ monlib = utils.restraints.load_monomer_library(st, monomer_dir=args.monlib, cif_files=args.ligand,
179
+ stop_for_unknowns=not args.newligand_continue,
180
+ params=params)
181
+ except RuntimeError as e:
182
+ raise SystemExit("Error: {}".format(e))
183
+ if not args.keep_entities:
184
+ utils.model.setup_entities(st, clear=True, force_subchain_names=True, overwrite_entity_type=True)
185
+ utils.restraints.find_and_fix_links(st, monlib, find_metal_links=args.find_links,
186
+ add_found=args.find_links)
187
+ h_change = {"all":gemmi.HydrogenChange.ReAddKnown,
188
+ "yes":gemmi.HydrogenChange.NoChange,
189
+ "no":gemmi.HydrogenChange.Remove}[args.hydrogen]
190
+ try:
191
+ topo, _ = utils.restraints.prepare_topology(st, monlib, h_change=h_change,
192
+ check_hydrogen=(args.hydrogen=="yes"),
193
+ params=params)
194
+ except RuntimeError as e:
195
+ raise SystemExit("Error: {}".format(e))
196
+
197
+ print_h_options(h_change, st[0].has_hydrogen(), args.refine_h, args.hout, geom_only=False)
198
+
199
+ # initialize ADP
200
+ utils.model.reset_adp(st[0], args.bfactor, args.adp)
201
+
202
+ # auto weight
203
+ if args.weight is None:
204
+ logger.writeln("Estimating weight using resolution")
205
+ reso = hkldata.d_min_max()[0]
206
+ args.weight = numpy.exp(reso * 0.9104 + 0.2162)
207
+ logger.writeln(" Will use weight= {:.2f}".format(args.weight))
208
+
209
+ if args.ncsr:
210
+ ncslist = utils.restraints.prepare_ncs_restraints(st)
211
+ else:
212
+ ncslist = False
213
+ geom = Geom(st, topo, monlib, shake_rms=args.randomize, adpr_w=args.adpr_weight, occr_w=args.occr_weight, params=params,
214
+ unrestrained=args.unrestrained or args.jellyonly, use_nucleus=(args.source=="neutron"),
215
+ ncslist=ncslist)
216
+ geom.geom.angle_von_mises = args.vonmises
217
+ geom.geom.adpr_max_dist = args.max_dist_for_adp_restraint
218
+ if args.adp_restraint_power is not None: geom.geom.adpr_d_power = args.adp_restraint_power
219
+ if args.adp_restraint_exp_fac is not None: geom.geom.adpr_exp_fac = args.adp_restraint_exp_fac
220
+ if args.adp_restraint_no_long_range: geom.geom.adpr_long_range = False
221
+ geom.geom.adpr_mode = args.adp_restraint_mode
222
+ if args.jellybody or args.jellyonly:
223
+ geom.geom.ridge_sigma, geom.geom.ridge_dmax = args.jellybody_params
224
+ if args.jellyonly: geom.geom.ridge_exclude_short_dist = False
225
+
226
+ ll = LL_Xtal(hkldata, centric_and_selections, args.free, st, monlib, source=args.source,
227
+ use_solvent=not args.no_solvent, use_in_est=use_in_est, use_in_target=use_in_target,
228
+ twin=args.twin)
229
+ refiner = Refine(st, geom, ll=ll,
230
+ refine_xyz=not args.fix_xyz,
231
+ adp_mode=dict(fix=0, iso=1, aniso=2)[args.adp],
232
+ refine_h=args.refine_h,
233
+ unrestrained=args.unrestrained,
234
+ params=params,
235
+ refine_occ=args.refine_all_occ)
236
+
237
+ stats = refiner.run_cycles(args.ncycle, weight=args.weight,
238
+ weight_adjust=not args.no_weight_adjust,
239
+ weight_adjust_bond_rmsz_range=args.target_bond_rmsz_range,
240
+ stats_json_out=args.output_prefix + "_stats.json")
241
+ update_meta(st, stats[-1], ll)
242
+ refiner.st.name = args.output_prefix
243
+ utils.fileio.write_model(refiner.st, args.output_prefix, pdb=True, cif=True, hout=args.hout)
244
+ if params["write_trajectory"]:
245
+ utils.fileio.write_model(refiner.st_traj, args.output_prefix + "_traj", cif=True)
246
+
247
+ if ll.twin_data:
248
+ # replace hkldata
249
+ hkldata = calculate_maps_twin(ll.hkldata, ll.b_aniso, ll.fc_labs, ll.D_labs, ll.twin_data,
250
+ centric_and_selections, use=use_in_target)
251
+ elif is_int:
252
+ calculate_maps_int(ll.hkldata, ll.b_aniso, ll.fc_labs, ll.D_labs, centric_and_selections,
253
+ use=use_in_target)
254
+ else:
255
+ calculate_maps(ll.hkldata, ll.b_aniso, centric_and_selections, ll.fc_labs, ll.D_labs, args.output_prefix + "_stats.log",
256
+ use=use_in_target)
257
+
258
+ # Write mtz file
259
+ if ll.twin_data:
260
+ labs = ["F_est", "F_exp", "FOM"]
261
+ elif is_int:
262
+ labs = ["I", "SIGI", "FOM"]
263
+ else:
264
+ labs = ["FP", "SIGFP", "FOM"]
265
+ labs.extend(["FWT", "DELFWT", "FC"])
266
+ if "FAN" in hkldata.df:
267
+ labs.append("FAN")
268
+ if not args.no_solvent:
269
+ labs.append("FCbulk")
270
+ if "FREE" in hkldata.df:
271
+ labs.append("FREE")
272
+ labs += ll.D_labs + ["S"] # for debugging, for now
273
+ mtz_out = args.output_prefix+".mtz"
274
+ hkldata.write_mtz(mtz_out, labs=labs, types={"FOM": "W", "FP":"F", "SIGFP":"Q", "I":"J", "SIGI":"Q", "F_est": "F", "F_exp": "F"})
275
+
276
+ # main()
277
+
278
+ if __name__ == "__main__":
279
+ import sys
280
+ args = parse_args(sys.argv[1:])
281
+ main(args)
@@ -0,0 +1,144 @@
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 scipy.sparse
13
+ from servalcat.utils import logger
14
+ from servalcat import utils
15
+ from servalcat.spa import fofc
16
+ from servalcat.spa import fsc
17
+ from servalcat import ext
18
+ b_to_u = utils.model.b_to_u
19
+ u_to_b = utils.model.u_to_b
20
+
21
+ def calc_D_and_S(hkldata, lab_obs): # simplified version of fofc.calc_D_and_S()
22
+ bdf = hkldata.binned_df
23
+ bdf["D"] = 0.
24
+ bdf["S"] = 0.
25
+ for i_bin, idxes in hkldata.binned():
26
+ Fo = hkldata.df[lab_obs].to_numpy()[idxes]
27
+ Fc = hkldata.df.FC.to_numpy()[idxes]
28
+ bdf.loc[i_bin, "D"] = numpy.nansum(numpy.real(Fo * numpy.conj(Fc))) / numpy.sum(numpy.abs(Fc)**2)
29
+ bdf.loc[i_bin, "S"] = numpy.nanmean(numpy.abs(Fo - bdf.D[i_bin] * Fc)**2)
30
+ # calc_D_and_S()
31
+
32
+ class LL_SPA:
33
+ def __init__(self, hkldata, st, monlib, lab_obs, source="electron", mott_bethe=True):
34
+ assert source in ("electron", "xray")
35
+ self.source = source
36
+ self.mott_bethe = False if source != "electron" else mott_bethe
37
+ self.hkldata = hkldata
38
+ self.lab_obs = lab_obs
39
+ self.st = st
40
+ self.monlib = monlib
41
+ self.d_min_max = hkldata.d_min_max()
42
+ self.ll = None
43
+ self.b_aniso = None
44
+
45
+ def refine_id(self):
46
+ if self.source == "electron":
47
+ return "ELECTRON MICROSCOPY"
48
+ return "NON-EM SPA" # does not happen, I guess
49
+
50
+ def update_ml_params(self):
51
+ # FIXME make sure D > 0
52
+ calc_D_and_S(self.hkldata, self.lab_obs)
53
+
54
+ def update_fc(self):
55
+ if self.st.ncs:
56
+ st = self.st.clone()
57
+ st.expand_ncs(gemmi.HowToNameCopiedChain.Short, merge_dist=0)
58
+ else:
59
+ st = self.st
60
+
61
+ self.hkldata.df["FC"] = utils.model.calc_fc_fft(st, self.d_min_max[0] - 1e-6,
62
+ monlib=self.monlib,
63
+ source=self.source,
64
+ mott_bethe=self.mott_bethe,
65
+ miller_array=self.hkldata.miller_array())
66
+
67
+ def prepare_target(self):
68
+ pass
69
+
70
+ def overall_scale(self, min_b=0.5):
71
+ k, b = self.hkldata.scale_k_and_b(lab_ref=self.lab_obs, lab_scaled="FC")
72
+ min_b_iso = self.st[0].calculate_b_aniso_range()[0] # actually min of aniso too
73
+ tmp = min_b_iso + b
74
+ if tmp < min_b: # perhaps better only adjust b_iso that went too small, but we need to recalculate Fc
75
+ logger.writeln("Adjusting overall B to avoid too small value")
76
+ b += min_b - tmp
77
+ logger.writeln("Applying overall B to model: {:.2f}".format(b))
78
+ utils.model.shift_b(self.st[0], b)
79
+ # adjust Fc
80
+ k_iso = self.hkldata.debye_waller_factors(b_iso=b)
81
+ self.hkldata.df["FC"] *= k_iso
82
+ # adjust Fo
83
+ self.hkldata.df[self.lab_obs] /= k
84
+ # overall_scale()
85
+
86
+ def calc_target(self): # -LL target for SPA
87
+ ret = 0
88
+ for i_bin, idxes in self.hkldata.binned():
89
+ Fo = self.hkldata.df[self.lab_obs].to_numpy()[idxes]
90
+ DFc = self.hkldata.df.FC.to_numpy()[idxes] * self.hkldata.binned_df.D[i_bin]
91
+ S = self.hkldata.binned_df.S[i_bin]
92
+ ret += numpy.nansum(numpy.abs(Fo - DFc)**2) / S + numpy.log(S) * len(idxes)
93
+ return ret * 2 # friedel mates
94
+ # calc_target()
95
+
96
+ def calc_stats(self, bin_stats=False):
97
+ # ignore bin_stats for now. better stats are calculated after refinement
98
+ stats = fsc.calc_fsc_all(self.hkldata, labs_fc=["FC"], lab_f=self.lab_obs)
99
+ fsca = fsc.fsc_average(stats.ncoeffs, stats.fsc_FC_full)
100
+ logger.writeln("FSCaverage = {:.4f}".format(fsca))
101
+ ret = {"summary": {"FSCaverage": fsca, "-LL": self.calc_target()}}
102
+ # XXX in fsc object, _full is misleading - it's not full in cross validation mode
103
+ if "D" in self.hkldata.binned_df and "S" in self.hkldata.binned_df:
104
+ stats[["D", "S"]] = self.hkldata.binned_df[["D", "S"]]
105
+ ret["bin_stats"] = stats
106
+ return ret
107
+
108
+ def calc_grad(self, atom_pos, refine_xyz, adp_mode, refine_occ, refine_h, specs):
109
+ dll_dab = numpy.empty_like(self.hkldata.df[self.lab_obs])
110
+ d2ll_dab2 = numpy.zeros(len(self.hkldata.df.index))
111
+ blur = utils.model.determine_blur_for_dencalc(self.st, self.d_min_max[0] / 3) # TODO need more work
112
+ logger.writeln("blur for deriv= {:.2f}".format(blur))
113
+ for i_bin, idxes in self.hkldata.binned():
114
+ D = self.hkldata.binned_df.D[i_bin]
115
+ S = self.hkldata.binned_df.S[i_bin]
116
+ Fc = self.hkldata.df.FC.to_numpy()[idxes]
117
+ Fo = self.hkldata.df[self.lab_obs].to_numpy()[idxes]
118
+ dll_dab[idxes] = -2 * D / S * (Fo - D * Fc)#.conj()
119
+ d2ll_dab2[idxes] = 2 * D**2 / S
120
+
121
+ if self.mott_bethe:
122
+ dll_dab *= self.hkldata.d_spacings()**2 * gemmi.mott_bethe_const()
123
+ d2ll_dab2 *= gemmi.mott_bethe_const()**2
124
+
125
+ # we need V for Hessian and V**2/n for gradient.
126
+ d2ll_dab2 *= self.hkldata.cell.volume
127
+ dll_dab_den = self.hkldata.fft_map(data=dll_dab * self.hkldata.debye_waller_factors(b_iso=-blur))
128
+ dll_dab_den.array[:] *= self.hkldata.cell.volume**2 / dll_dab_den.point_count
129
+ self.ll = ext.LL(self.st, atom_pos, self.mott_bethe, refine_xyz, adp_mode, refine_occ, refine_h)
130
+ self.ll.set_ncs([x.tr for x in self.st.ncs if not x.given])
131
+ self.ll.calc_grad_it92(dll_dab_den, blur)
132
+
133
+ # second derivative
134
+ d2dfw_table = ext.TableS3(*self.hkldata.d_min_max())
135
+ d2dfw_table.make_table(1./self.hkldata.d_spacings(), d2ll_dab2)
136
+ self.ll.make_fisher_table_diag_fast_it92(d2dfw_table)
137
+ self.ll.fisher_diag_from_table_it92()
138
+ #json.dump(dict(b=ll.table_bs, pp1=ll.pp1, bb=ll.bb),
139
+ # open("ll_fisher.json", "w"), indent=True)
140
+ #a, (b,c) = ll.fisher_for_coo()
141
+ #json.dump(([float(x) for x in a], ([int(x) for x in b], [int(x) for x in c])), open("fisher.json", "w"))
142
+ #logger.writeln("disabling spec_correction in spa target")
143
+ if specs is not None:
144
+ self.ll.spec_correction(specs, use_rr=False)