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