1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 from re import search
25 from warnings import warn
26
27
28 from generic_fns.interatomic import return_interatom_list
29 from generic_fns.mol_res_spin import exists_mol_res_spin_data, return_spin, spin_loop
30 from generic_fns import pipes
31 from maths_fns.consistency_tests import Consistency
32 from physical_constants import N15_CSA, NH_BOND_LENGTH, h_bar, mu0, return_gyromagnetic_ratio
33 from relax_errors import RelaxError, RelaxFuncSetupError, RelaxNoSequenceError, RelaxNoValueError, RelaxSpinTypeError
34 from relax_warnings import RelaxDeselectWarning
35 import specific_fns
36 from specific_fns.api_base import API_base
37 from specific_fns.api_common import API_common
38 from user_functions.data import Uf_tables; uf_tables = Uf_tables()
39 from user_functions.objects import Desc_container
40
41
43 """Class containing functions specific to consistency testing."""
44
46 """Initialise the class by placing API_common methods into the API."""
47
48
49 super(Consistency_tests, self).__init__()
50
51
52 self.base_data_loop = self._base_data_loop_spin
53 self.create_mc_data = self._create_mc_relax_data
54 self.model_loop = self._model_loop_spin
55 self.return_conversion_factor = self._return_no_conversion_factor
56 self.return_error = self._return_error_relax_data
57 self.return_value = self._return_value_general
58 self.set_param_values = self._set_param_values_spin
59 self.set_selected_sim = self._set_selected_sim_spin
60 self.sim_pack_data = self._sim_pack_relax_data
61
62
63 self.PARAMS.add('j0', scope='spin', desc='Spectral density value at 0 MHz (from Farrow et al. (1995) JBNMR, 6: 153-162)', py_type=float, grace_string='\\qJ(0)\\Q', err=True, sim=True)
64 self.PARAMS.add('f_eta', scope='spin', desc='Eta-test (from Fushman et al. (1998) JACS, 120: 10947-10952)', py_type=float, grace_string='\\qF\\s\\xh\\Q', err=True, sim=True)
65 self.PARAMS.add('f_r2', scope='spin', desc='R2-test (from Fushman et al. (1998) JACS, 120: 10947-10952)', py_type=float, grace_string='\\qF\\sR2\\Q', err=True, sim=True)
66 self.PARAMS.add('csa', scope='spin', default=N15_CSA, units='ppm', desc='CSA value', py_type=float, grace_string='\\qCSA\\Q')
67 self.PARAMS.add('orientation', scope='spin', default=15.7, units='degrees', desc="Angle between the 15N-1H vector and the principal axis of the 15N chemical shift tensor", py_type=float, grace_string='\\q\\xq\\Q')
68 self.PARAMS.add('tc', scope='spin', default=13 * 1e-9, units='ns', desc="Correlation time", py_type=float, grace_string='\\q\\xt\\f{}c\\Q')
69
70
72 """Function for selecting which relaxation data to use in the consistency tests."""
73
74
75 pipes.test()
76
77
78 function_type = cdp.pipe_type
79 if function_type != 'ct':
80 raise RelaxFuncSetupError(specific_fns.setup.get_string(function_type))
81
82
83 if hasattr(cdp, 'ct_frq'):
84 raise RelaxError("The frequency for the run has already been set.")
85
86
87 if not hasattr(cdp, 'ct_frq'):
88 cdp.ct_frq = {}
89
90
91 cdp.ct_frq = frq
92
93
94 - def calculate(self, spin_id=None, verbosity=1, sim_index=None):
95 """Calculation of the consistency functions.
96
97 @keyword spin_id: The spin identification string.
98 @type spin_id: None or str
99 @keyword verbosity: The amount of information to print. The higher the value, the greater the verbosity.
100 @type verbosity: int
101 @keyword sim_index: The optional MC simulation index.
102 @type sim_index: None or int
103 """
104
105
106 if not hasattr(cdp, 'ct_frq') or not isinstance(cdp.ct_frq, float):
107 raise RelaxError("The frequency has not been set up.")
108
109
110 if not exists_mol_res_spin_data():
111 raise RelaxNoSequenceError
112
113
114 for spin, id in spin_loop(spin_id, return_id=True):
115
116 if not spin.select:
117 continue
118
119
120 if not hasattr(spin, 'isotope'):
121 raise RelaxSpinTypeError
122
123
124 if not hasattr(spin, 'csa') or spin.csa == None:
125 raise RelaxNoValueError("CSA")
126
127
128 if not hasattr(spin, 'orientation') or spin.orientation == None:
129 raise RelaxNoValueError("angle Theta")
130
131
132 if not hasattr(spin, 'tc') or spin.tc == None:
133 raise RelaxNoValueError("correlation time")
134
135
136 interatoms = return_interatom_list(id)
137 for interatom in interatoms:
138
139 if not interatom.dipole_pair:
140 continue
141
142
143 if id != interatom.spin_id1:
144 spin_id2 = interatom.spin_id1
145 else:
146 spin_id2 = interatom.spin_id2
147 spin2 = return_spin(spin_id2)
148
149
150 if not hasattr(spin2, 'isotope'):
151 raise RelaxSpinTypeError
152
153
154 if not hasattr(interatom, 'r') or interatom.r == None:
155 raise RelaxNoValueError("interatomic distance", spin_id=spin_id, spin_id2=spin_id2)
156
157
158 if cdp.ct_frq not in cdp.frq.values():
159 raise RelaxError("No relaxation data corresponding to the frequency %s has been loaded." % cdp.ct_frq)
160
161
162 for spin, id in spin_loop(spin_id, return_id=True):
163
164 if not spin.select:
165 continue
166
167
168 r1 = None
169 r2 = None
170 noe = None
171
172
173 for ri_id in cdp.ri_ids:
174
175 if cdp.frq[ri_id] != cdp.ct_frq:
176 continue
177
178
179 if cdp.ri_type[ri_id] == 'R1':
180 if sim_index == None:
181 r1 = spin.ri_data[ri_id]
182 else:
183 r1 = spin.ri_data_sim[ri_id][sim_index]
184
185
186 if cdp.ri_type[ri_id] == 'R2':
187 if sim_index == None:
188 r2 = spin.ri_data[ri_id]
189 else:
190 r2 = spin.ri_data_sim[ri_id][sim_index]
191
192
193 if cdp.ri_type[ri_id] == 'NOE':
194 if sim_index == None:
195 noe = spin.ri_data[ri_id]
196 else:
197 noe = spin.ri_data_sim[ri_id][sim_index]
198
199
200 if r1 == None or r2 == None or noe == None:
201 continue
202
203
204 interatoms = return_interatom_list(id)
205 for i in range(len(interatoms)):
206
207 if not interatoms[i].dipole_pair:
208 continue
209
210
211 if id != interatoms[i].spin_id1:
212 spin_id2 = interatoms[i].spin_id1
213 else:
214 spin_id2 = interatoms[i].spin_id2
215 spin2 = return_spin(spin_id2)
216
217
218 gx = return_gyromagnetic_ratio(spin.isotope)
219 gh = return_gyromagnetic_ratio(spin2.isotope)
220
221
222 r = interatoms[i].r
223
224
225 self.ct = Consistency(frq=cdp.ct_frq, gx=gx, gh=gh, mu0=mu0, h_bar=h_bar)
226
227
228 j0, f_eta, f_r2 = self.ct.func(orientation=spin.orientation, tc=spin.tc, r=r, csa=spin.csa, r1=r1, r2=r2, noe=noe)
229
230
231 if sim_index == None:
232 spin.j0 = j0
233 spin.f_eta = f_eta
234 spin.f_r2 = f_r2
235
236
237 else:
238
239 self.data_init(spin, sim=1)
240 if spin.j0_sim == None:
241 spin.j0_sim = []
242 spin.f_eta_sim = []
243 spin.f_r2_sim = []
244
245
246 spin.j0_sim.append(j0)
247 spin.f_eta_sim.append(f_eta)
248 spin.f_r2_sim.append(f_r2)
249
250
252 """Initialise the data structures.
253
254 @param data_cont: The data container.
255 @type data_cont: instance
256 @keyword sim: The Monte Carlo simulation flag, which if true will initialise the simulation data structure.
257 @type sim: bool
258 """
259
260
261 data_names = self.data_names()
262
263
264 for name in data_names:
265
266 if sim:
267
268 name = name + '_sim'
269
270
271 if not hasattr(data_cont, name):
272
273 setattr(data_cont, name, None)
274
275
276 default_value_doc = Desc_container("Consistency testing default values")
277 default_value_doc.add_paragraph("These default values are found in the file 'physical_constants.py'.")
278 _table = uf_tables.add_table(label="table: consistency testing default values", caption="Consistency testing default values.")
279 _table.add_headings(["Data type", "Object name", "Value"])
280 _table.add_row(["Bond length", "'r'", "1.02 * 1e-10"])
281 _table.add_row(["CSA", "'csa'", "-172 * 1e-6"])
282 _table.add_row(["Heteronucleus type", "'heteronuc_type'", "'15N'"])
283 _table.add_row(["Angle theta", "'proton_type'", "'1H'"])
284 _table.add_row(["Proton type", "'orientation'", "15.7"])
285 _table.add_row(["Correlation time", "'tc'", "13 * 1e-9"])
286 default_value_doc.add_table(_table.label)
287
288
290 """Deselect spins which have insufficient data to support calculation.
291
292 @keyword data_check: A flag to signal if the presence of base data is to be checked for.
293 @type data_check: bool
294 @keyword verbose: A flag which if True will allow printouts.
295 @type verbose: bool
296 """
297
298
299 if verbose:
300 print("\nOver-fit spin deselection:")
301
302
303 if not exists_mol_res_spin_data():
304 raise RelaxNoSequenceError
305
306
307 deselect_flag = False
308 for spin, spin_id in spin_loop(return_id=True):
309
310 if not spin.select:
311 continue
312
313
314 if not hasattr(spin, 'ri_data'):
315 warn(RelaxDeselectWarning(spin_id, 'missing relaxation data'))
316 spin.select = False
317 deselect_flag = True
318 continue
319
320
321 else:
322
323 data_points = 0
324 for id in cdp.ri_ids:
325 if id in spin.ri_data and spin.ri_data[id] != None:
326 data_points += 1
327
328
329 if data_points < 3:
330 warn(RelaxDeselectWarning(spin_id, 'insufficient relaxation data, 3 or more data points are required'))
331 spin.select = False
332 deselect_flag = True
333 continue
334
335
336 if verbose and not deselect_flag:
337 print("No spins have been deselected.")
338
339
340 return_data_name_doc = Desc_container("Consistency testing data type string matching patterns")
341 _table = uf_tables.add_table(label="table: Consistency testing data types", caption="Consistency testing data type string matching patterns.")
342 _table.add_headings(["Data type", "Object name"])
343 _table.add_row(["J(0)", "'j0'"])
344 _table.add_row(["F_eta", "'f_eta'"])
345 _table.add_row(["F_R2", "'f_r2'"])
346 _table.add_row(["Bond length", "'r'"])
347 _table.add_row(["CSA", "'csa'"])
348 _table.add_row(["Heteronucleus type", "'heteronuc_type'"])
349 _table.add_row(["Proton type", "'proton_type'"])
350 _table.add_row(["Angle theta", "'orientation'"])
351 _table.add_row(["Correlation time", "'tc'"])
352 return_data_name_doc.add_table(_table.label)
353
354
355 set_doc = Desc_container("Consistency testing set details")
356 set_doc.add_paragraph("In consistency testing, only four values can be set, the bond length, CSA, angle Theta ('orientation') and correlation time values. These must be set prior to the calculation of consistency functions.")
357
358
359 - def set_error(self, model_info, index, error):
360 """Set the parameter errors.
361
362 @param model_info: The spin container originating from model_loop().
363 @type model_info: SpinContainer instance
364 @param index: The index of the parameter to set the errors for.
365 @type index: int
366 @param error: The error value.
367 @type error: float
368 """
369
370
371 spin = model_info
372
373
374 if index == 0:
375 spin.j0_err = error
376
377
378 if index == 1:
379 spin.f_eta_err = error
380
381
382 if index == 2:
383 spin.f_r2_err = error
384
385
387 """Return the array of simulation parameter values.
388
389 @param model_info: The spin container originating from model_loop().
390 @type model_info: SpinContainer instance
391 @param index: The index of the parameter to return the array of values for.
392 @type index: int
393 @return: The array of simulation parameter values.
394 @rtype: list of float
395 """
396
397
398 spin = model_info
399
400
401 if not spin.select:
402 return
403
404
405 if index == 0:
406 return spin.j0_sim
407
408
409 if index == 1:
410 return spin.f_eta_sim
411
412
413 if index == 2:
414 return spin.f_r2_sim
415
416
418 """Return the array of selected simulation flags.
419
420 @param model_info: The spin container originating from model_loop().
421 @type model_info: SpinContainer instance
422 @return: The array of selected simulation flags.
423 @rtype: list of int
424 """
425
426
427 spin = model_info
428
429
430 return spin.select_sim
431