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