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