1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """Module for the manipulation of RDC data."""
24
25
26 from copy import deepcopy
27 from math import pi, sqrt
28 from numpy import array, int32, float64, ones, transpose, zeros
29 from numpy.linalg import norm
30 import sys
31 from warnings import warn
32
33
34 from lib.check_types import is_float
35 from lib.float import nan
36 from lib.alignment.rdc import ave_rdc_tensor
37 from lib.errors import RelaxError, RelaxNoAlignError, RelaxNoJError, RelaxNoRDCError, RelaxNoSequenceError, RelaxSpinTypeError
38 from lib.io import extract_data, open_write_file, strip, write_data
39 from lib.physical_constants import dipolar_constant, return_gyromagnetic_ratio
40 from lib.warnings import RelaxWarning, RelaxSpinTypeWarning
41 from pipe_control import grace, pipes
42 from pipe_control.align_tensor import get_tensor_index, get_tensor_object, opt_uses_align_data, opt_uses_tensor
43 from pipe_control.interatomic import consistent_interatomic_data, create_interatom, interatomic_loop, return_interatom
44 from pipe_control.mol_res_spin import exists_mol_res_spin_data, is_pseudoatom, pseudoatom_loop, return_spin
45
46
48 """Back calculate the RDC from the alignment tensor and unit bond vectors.
49
50 @keyword align_id: The alignment tensor ID string.
51 @type align_id: str
52 """
53
54
55 check_pipe_setup(rdc_id=align_id, sequence=True, N=True, tensors=True)
56
57
58 if align_id:
59 align_ids = [align_id]
60 else:
61 align_ids = cdp.align_ids
62
63
64 for align_id in align_ids:
65
66 if not hasattr(cdp, 'rdc_ids'):
67 cdp.rdc_ids = []
68
69
70 if align_id not in cdp.rdc_ids:
71 cdp.rdc_ids.append(align_id)
72
73
74 weights = ones(cdp.N, float64) / cdp.N
75
76
77 unit_vect = zeros((cdp.N, 3), float64)
78
79
80 count = 0
81 for interatom in interatomic_loop():
82
83 if not hasattr(interatom, 'vector'):
84 continue
85
86
87 spin1 = return_spin(interatom.spin_id1)
88 spin2 = return_spin(interatom.spin_id2)
89
90
91 if not hasattr(spin1, 'isotope'):
92 raise RelaxSpinTypeError(interatom.spin_id1)
93 if not hasattr(spin2, 'isotope'):
94 raise RelaxSpinTypeError(interatom.spin_id2)
95
96
97 if is_float(interatom.vector[0]):
98 vectors = [interatom.vector]
99 else:
100 vectors = interatom.vector
101
102
103 g1 = return_gyromagnetic_ratio(spin1.isotope)
104 g2 = return_gyromagnetic_ratio(spin2.isotope)
105
106
107 dj = 3.0/(2.0*pi) * dipolar_constant(g1, g2, interatom.r)
108
109
110 for c in range(cdp.N):
111 unit_vect[c] = vectors[c] / norm(vectors[c])
112
113
114 if not hasattr(interatom, 'rdc_bc'):
115 interatom.rdc_bc = {}
116
117
118 for id in align_ids:
119
120 interatom.rdc_bc[id] = ave_rdc_tensor(dj, unit_vect, cdp.N, cdp.align_tensors[get_tensor_index(align_id=id)].A, weights=weights)
121
122
123 if hasattr(interatom, 'rdc_data_types') and align_id in interatom.rdc_data_types and interatom.rdc_data_types[align_id] == 'T':
124 if not hasattr(interatom, 'j_coupling'):
125 raise RelaxNoJError
126
127 interatom.rdc_bc[id] += interatom.j_coupling
128
129
130 if hasattr(interatom, 'absolute_rdc') and id in interatom.absolute_rdc.keys() and interatom.absolute_rdc[id]:
131 interatom.rdc_bc[id] = abs(interatom.rdc_bc[id])
132
133
134 count += 1
135
136
137 if not count:
138 warn(RelaxWarning("No RDCs have been back calculated, probably due to missing bond vector information."))
139
140
141 -def check_pipe_setup(pipe=None, rdc_id=None, sequence=False, N=False, tensors=False, rdc=False):
142 """Check that the current data pipe has been setup sufficiently.
143
144 @keyword pipe: The data pipe to check, defaulting to the current pipe.
145 @type pipe: None or str
146 @keyword rdc_id: The RDC ID string to check for in cdp.rdc_ids.
147 @type rdc_id: None or str
148 @keyword sequence: A flag which when True will invoke the sequence data check.
149 @type sequence: bool
150 @keyword N: A flag which if True will check that cdp.N is set.
151 @type N: bool
152 @keyword tensors: A flag which if True will check that alignment tensors exist.
153 @type tensors: bool
154 @keyword rdc: A flag which if True will check that RDCs exist.
155 @type rdc: bool
156 """
157
158
159 if pipe == None:
160 pipe = pipes.cdp_name()
161
162
163 dp = pipes.get_pipe(pipe)
164
165
166 pipes.test(pipe)
167
168
169 if sequence and not exists_mol_res_spin_data(pipe):
170 raise RelaxNoSequenceError(pipe)
171
172
173 if N and not hasattr(dp, 'N'):
174 raise RelaxError("The number of states N has not been set.")
175
176
177 if tensors and (not hasattr(dp, 'align_tensors') or len(dp.align_tensors) == 0):
178 raise RelaxNoTensorError('alignment')
179
180
181 if rdc_id and (not hasattr(dp, 'align_ids') or rdc_id not in dp.align_ids):
182 raise RelaxNoAlignError(rdc_id, pipe)
183
184
185 if rdc and not hasattr(dp, 'align_ids'):
186 raise RelaxNoAlignError()
187 if rdc and not hasattr(dp, 'rdc_ids'):
188 raise RelaxNoRDCError()
189 elif rdc and rdc_id and rdc_id not in dp.rdc_ids:
190 raise RelaxNoRDCError(rdc_id)
191
192
194 """Check if all data required for calculating the RDC is present.
195
196 @param interatom: The interatomic data container.
197 @type interatom: InteratomContainer instance
198 @return: True if all data required for calculating the RDC is present, False otherwise.
199 @rtype: bool
200 """
201
202
203 if not interatom.select:
204 return False
205
206
207 if not hasattr(interatom, 'rdc'):
208 return False
209
210
211 if opt_uses_j_couplings() and not hasattr(interatom, 'j_coupling'):
212 return False
213
214
215 spin1 = return_spin(interatom.spin_id1)
216 spin2 = return_spin(interatom.spin_id2)
217
218
219 if not hasattr(spin1, 'isotope'):
220 warn(RelaxSpinTypeWarning(interatom.spin_id1))
221 return False
222 if not hasattr(spin2, 'isotope'):
223 warn(RelaxSpinTypeWarning(interatom.spin_id2))
224 return False
225 if is_pseudoatom(spin1) and is_pseudoatom(spin2):
226 warn(RelaxWarning("Support for both spins being in a dipole pair being pseudo-atoms is not implemented yet."))
227 return False
228
229
230 if is_pseudoatom(spin1) or is_pseudoatom(spin2):
231
232 pseudospin = spin1
233 base_spin_id = interatom.spin_id2
234 pseudospin_id = interatom.spin_id1
235 if is_pseudoatom(spin2):
236 pseudospin = spin2
237 base_spin_id = interatom.spin_id1
238 pseudospin_id = interatom.spin_id2
239
240
241 for spin, spin_id in pseudoatom_loop(pseudospin, return_id=True):
242
243 pseudo_interatom = return_interatom(spin_id1=spin_id, spin_id2=base_spin_id)
244
245
246 if not hasattr(pseudo_interatom, 'vector'):
247 warn(RelaxWarning("The interatomic vector is missing for the spin pair '%s' and '%s' of the pseudo-atom '%s', skipping the RDC for the spin pair '%s' and '%s'." % (pseudo_interatom.spin_id1, pseudo_interatom.spin_id2, pseudospin_id, base_spin_id, pseudospin_id)))
248 return False
249
250
251 if not hasattr(pseudo_interatom, 'r'):
252 warn(RelaxWarning("The averaged interatomic distance between spins '%s' and '%s' for the pseudo-atom '%s' has not been set yet." % (spin_id, base_spin_id, pseudospin_id)))
253 return False
254
255
256 else:
257
258 if not hasattr(interatom, 'vector'):
259 warn(RelaxWarning("The interatomic vector is missing, skipping the spin pair '%s' and '%s'." % (interatom.spin_id1, interatom.spin_id2)))
260 return False
261
262
263 if not hasattr(interatom, 'r'):
264 warn(RelaxWarning("The averaged interatomic distance between spins '%s' and '%s' has not been set yet." % (interatom.spin_id1, interatom.spin_id2)))
265 return False
266
267
268 return True
269
270
271 -def convert(value, data_type, align_id, to_intern=False):
272 """Convert the RDC based on the 'D' or '2D' data type.
273
274 @param value: The value or error to convert.
275 @type value: float or None
276 @param data_type: The RDC data type. Either 'D', '2D' or 'T'.
277 @type data_type: str
278 @param align_id: The alignment tensor ID string.
279 @type align_id: str
280 @keyword to_intern: A flag which if True will convert to the internal D notation if needed, or if False will convert from the internal D notation to the external D or 2D format.
281 @type to_intern: bool
282 @return: The converted value.
283 @rtype: float or None
284 """
285
286
287 if value == None:
288 return None
289
290
291 factor = 1.0
292 if data_type == '2D':
293
294 if to_intern:
295 factor = 2.0
296
297
298 else:
299 factor = 0.5
300
301
302 return value * factor
303
304
305 -def copy(pipe_from=None, pipe_to=None, align_id=None):
306 """Copy the RDC data from one data pipe to another.
307
308 @keyword pipe_from: The data pipe to copy the RDC data from. This defaults to the current data pipe.
309 @type pipe_from: str
310 @keyword pipe_to: The data pipe to copy the RDC data to. This defaults to the current data pipe.
311 @type pipe_to: str
312 @param align_id: The alignment ID string.
313 @type align_id: str
314 """
315
316
317 if pipe_from == None and pipe_to == None:
318 raise RelaxError("The pipe_from and pipe_to arguments cannot both be set to None.")
319 elif pipe_from == None:
320 pipe_from = pipes.cdp_name()
321 elif pipe_to == None:
322 pipe_to = pipes.cdp_name()
323
324
325 check_pipe_setup(pipe=pipe_from, rdc_id=align_id, sequence=True, rdc=True)
326 check_pipe_setup(pipe=pipe_to, sequence=True)
327
328
329 dp_from = pipes.get_pipe(pipe_from)
330 dp_to = pipes.get_pipe(pipe_to)
331
332
333 consistent_interatomic_data(pipe1=pipe_to, pipe2=pipe_from)
334
335
336 if align_id == None:
337 align_ids = dp_from.align_ids
338 else:
339 align_ids = [align_id]
340
341
342 if not hasattr(dp_to, 'align_ids'):
343 dp_to.align_ids = []
344 if not hasattr(dp_to, 'rdc_ids'):
345 dp_to.rdc_ids = []
346
347
348 for align_id in align_ids:
349
350 if align_id not in dp_to.align_ids and align_id not in dp_to.align_ids:
351 dp_to.align_ids.append(align_id)
352 if align_id in dp_from.rdc_ids and align_id not in dp_to.rdc_ids:
353 dp_to.rdc_ids.append(align_id)
354
355
356 for i in range(len(dp_from.interatomic)):
357
358 interatom_from = dp_from.interatomic[i]
359 interatom_to = dp_to.interatomic[i]
360
361
362 if (not hasattr(interatom_from, 'rdc') or not align_id in interatom_from.rdc) and (not hasattr(interatom_from, 'rdc_err') or not align_id in interatom_from.rdc_err):
363 continue
364
365
366 if hasattr(interatom_from, 'rdc') and not hasattr(interatom_to, 'rdc'):
367 interatom_to.rdc = {}
368 if hasattr(interatom_from, 'rdc_err') and not hasattr(interatom_to, 'rdc_err'):
369 interatom_to.rdc_err = {}
370
371
372 if hasattr(interatom_from, 'rdc'):
373 interatom_to.rdc[align_id] = interatom_from.rdc[align_id]
374 if hasattr(interatom_from, 'rdc_err'):
375 interatom_to.rdc_err[align_id] = interatom_from.rdc_err[align_id]
376
377
378 -def corr_plot(format=None, title=None, subtitle=None, file=None, dir=None, force=False):
379 """Generate a correlation plot of the measured vs. back-calculated RDCs.
380
381 @keyword format: The format for the plot file. The following values are accepted: 'grace', a Grace plot; None, a plain text file.
382 @type format: str or None
383 @keyword title: The title for the plot, overriding the default.
384 @type title: None or str
385 @keyword subtitle: The subtitle for the plot, overriding the default.
386 @type subtitle: None or str
387 @keyword file: The file name or object to write to.
388 @type file: str or file object
389 @keyword dir: The name of the directory to place the file into (defaults to the current directory).
390 @type dir: str
391 @keyword force: A flag which if True will cause any pre-existing file to be overwritten.
392 @type force: bool
393 """
394
395
396 check_pipe_setup(sequence=True)
397
398
399 if not hasattr(cdp, 'rdc_ids') or not cdp.rdc_ids:
400 warn(RelaxWarning("No RDC data exists, skipping file creation."))
401 return
402
403
404 file = open_write_file(file, dir, force)
405
406
407 data = []
408 orig_title = title
409 if orig_title == None:
410 title = "RDC correlation plot"
411 axis_labels = ["Measured RDC (Hz)", "Back-calculated RDC (Hz)"]
412
413
414 data.append([[-100, -100, 0], [100, 100, 0]])
415
416
417 for align_id in cdp.rdc_ids:
418
419 data.append([])
420
421
422 err_flag = False
423 for interatom in interatomic_loop():
424
425 if hasattr(interatom, 'rdc_err') and align_id in interatom.rdc_err.keys():
426 err_flag = True
427 break
428
429
430 for interatom in interatomic_loop():
431
432 if not hasattr(interatom, 'rdc') or not hasattr(interatom, 'rdc_bc') or not align_id in interatom.rdc.keys() or not align_id in interatom.rdc_bc.keys():
433 continue
434
435
436 rdc_bc = convert(interatom.rdc_bc[align_id], interatom.rdc_data_types[align_id], align_id)
437 rdc = convert(interatom.rdc[align_id], interatom.rdc_data_types[align_id], align_id)
438
439
440 if hasattr(interatom, 'rdc_data_types') and align_id in interatom.rdc_data_types and interatom.rdc_data_types[align_id] == 'T':
441
442 if not interatom.absolute_rdc[align_id]:
443 rdc_bc -= interatom.j_coupling
444 rdc -= interatom.j_coupling
445
446
447 else:
448 if orig_title == None:
449 title = "T = J+D correlation plot"
450 axis_labels = ["Measured T = J+D (Hz)", "Back-calculated T = J+D (Hz)"]
451
452
453 data[-1].append([rdc, rdc_bc])
454
455
456 if err_flag:
457 if hasattr(interatom, 'rdc_err') and align_id in interatom.rdc_err.keys():
458 data[-1][-1].append(convert(interatom.rdc_err[align_id], interatom.rdc_data_types[align_id], align_id))
459 else:
460 data[-1][-1].append(None)
461
462
463 data[-1][-1].append("%s-%s" % (interatom.spin_id1, interatom.spin_id2))
464
465
466 size = len(data)
467
468
469 data = [data]
470
471
472 if err_flag:
473 graph_type = 'xydy'
474 else:
475 graph_type = 'xy'
476
477
478 if format == 'grace':
479
480 grace.write_xy_header(file=file, title=title, subtitle=subtitle, world=[[-50, -50, 50, 50]], sets=[size], set_names=[[None]+cdp.rdc_ids], linestyle=[[2]+[0]*size], data_type=['rdc', 'rdc_bc'], axis_labels=[axis_labels], tick_major_spacing=[[10, 10]], tick_minor_count=[[9, 9]], legend_pos=[[1, 0.5]])
481
482
483 grace.write_xy_data(data=data, file=file, graph_type=graph_type, autoscale=False)
484
485
487 """Delete the RDC data corresponding to the alignment ID.
488
489 @keyword align_id: The alignment tensor ID string. If not specified, all data will be deleted.
490 @type align_id: str or None
491 """
492
493
494 check_pipe_setup(sequence=True, rdc_id=align_id, rdc=True)
495
496
497 if not align_id:
498 ids = deepcopy(cdp.rdc_ids)
499 else:
500 ids = [align_id]
501
502
503 for id in ids:
504
505 cdp.rdc_ids.pop(cdp.rdc_ids.index(id))
506
507
508 for interatom in interatomic_loop():
509
510 if hasattr(interatom, 'rdc') and id in interatom.rdc:
511 interatom.rdc.pop(id)
512
513
514 if hasattr(interatom, 'rdc_err') and id in interatom.rdc_err:
515 interatom.rdc_err.pop(id)
516
517
518 if hasattr(interatom, 'rdc_data_types') and id in interatom.rdc_data_types:
519 interatom.rdc_data_types.pop(id)
520
521
522 if not hasattr(cdp, 'pcs_ids') or id not in cdp.pcs_ids:
523 cdp.align_ids.pop(cdp.align_ids.index(id))
524
525
526 -def display(align_id=None, bc=False):
527 """Display the RDC data corresponding to the alignment ID.
528
529 @keyword align_id: The alignment tensor ID string.
530 @type align_id: str
531 @keyword bc: The back-calculation flag which if True will cause the back-calculated rather than measured data to be displayed.
532 @type bc: bool
533 """
534
535
536 check_pipe_setup(sequence=True, rdc_id=align_id, rdc=True)
537
538
539 write(align_id=align_id, file=sys.stdout, bc=bc)
540
541
543 """Determine of J couplings are needed for optimisation.
544
545 @return: True if J couplings are required, False otherwise.
546 @rtype: bool
547 """
548
549
550 for align_id in cdp.align_ids:
551 for interatom in interatomic_loop():
552 if hasattr(interatom, 'rdc_data_types') and align_id in interatom.rdc_data_types and interatom.rdc_data_types[align_id] == 'T':
553 return True
554
555
556 return False
557
558
560 """Determine if the RDC data for the given alignment ID is needed for optimisation.
561
562 @param align_id: The alignment ID string.
563 @type align_id: str
564 @return: True if the RDC data is to be used for optimisation, False otherwise.
565 @rtype: bool
566 """
567
568
569 if not hasattr(cdp, 'rdc_ids'):
570 return False
571
572
573 if align_id not in cdp.rdc_ids:
574 return False
575
576
577 tensor_flag = opt_uses_tensor(get_tensor_object(align_id))
578
579
580 pos_flag = False
581 if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
582 pos_flag = True
583
584
585 prob_flag = False
586 if cdp.model == 'population':
587 prob_flag = True
588
589
590 if not tensor_flag and not pos_flag and not prob_flag:
591 return False
592
593
594 return True
595
596
598 """Calculate the Q factors for the RDC data.
599
600 @keyword spin_id: The spin ID string used to restrict the Q factor calculation to a subset of all spins.
601 @type spin_id: None or str
602 """
603
604
605 check_pipe_setup(sequence=True)
606
607
608 if not hasattr(cdp, 'rdc_ids') or not len(cdp.rdc_ids):
609 warn(RelaxWarning("No RDC data exists, Q factors cannot be calculated."))
610 return
611
612
613 cdp.q_factors_rdc = {}
614 cdp.q_factors_rdc_norm2 = {}
615
616
617 for align_id in cdp.rdc_ids:
618
619 D2_sum = 0.0
620 sse = 0.0
621
622
623 dj = None
624 N = 0
625 interatom_count = 0
626 rdc_data = False
627 rdc_bc_data = False
628 norm2_flag = True
629 for interatom in interatomic_loop():
630
631 interatom_count += 1
632
633
634 if hasattr(interatom, 'rdc') and align_id in interatom.rdc:
635 rdc_data = True
636 if hasattr(interatom, 'rdc_bc') and align_id in interatom.rdc_bc:
637 rdc_bc_data = True
638 j_flag = False
639 if hasattr(interatom, 'rdc_data_types') and align_id in interatom.rdc_data_types and interatom.rdc_data_types[align_id] == 'T':
640 j_flag = True
641 if not hasattr(interatom, 'j_coupling'):
642 raise RelaxNoJError
643
644
645 if not hasattr(interatom, 'rdc') or not hasattr(interatom, 'rdc_bc') or not align_id in interatom.rdc or interatom.rdc[align_id] == None or not align_id in interatom.rdc_bc or interatom.rdc_bc[align_id] == None:
646 continue
647
648
649 spin1 = return_spin(interatom.spin_id1)
650 spin2 = return_spin(interatom.spin_id2)
651
652
653 sse = sse + (interatom.rdc[align_id] - interatom.rdc_bc[align_id])**2
654
655
656 if j_flag:
657 D2_sum = D2_sum + (interatom.rdc[align_id] - interatom.j_coupling)**2
658 else:
659 D2_sum = D2_sum + interatom.rdc[align_id]**2
660
661
662 g1 = return_gyromagnetic_ratio(spin1.isotope)
663 g2 = return_gyromagnetic_ratio(spin2.isotope)
664
665
666 if norm2_flag and (is_pseudoatom(spin1) or is_pseudoatom(spin2)):
667 warn(RelaxWarning("Pseudo-atoms are present, skipping the Q factor normalised with 2Da^2(4 + 3R)/5."))
668 norm2_flag = False
669
670
671 if norm2_flag:
672 dj_new = 3.0/(2.0*pi) * dipolar_constant(g1, g2, interatom.r)
673 if dj != None and dj_new != dj:
674 warn(RelaxWarning("The dipolar constant is not the same for all RDCs, skipping the Q factor normalised with 2Da^2(4 + 3R)/5."))
675 norm2_flag = False
676 else:
677 dj = dj_new
678
679
680 N = N + 1
681
682
683 if not interatom_count:
684 warn(RelaxWarning("No interatomic data containers have been used in the calculation, skipping the RDC Q factor calculation."))
685 return
686 if not rdc_data:
687 warn(RelaxWarning("No RDC data can be found for the alignment ID '%s', skipping the RDC Q factor calculation for this alignment." % align_id))
688 continue
689 if not rdc_bc_data:
690 warn(RelaxWarning("No back-calculated RDC data can be found for the alignment ID '%s', skipping the RDC Q factor calculation for this alignment." % align_id))
691 continue
692
693
694 if norm2_flag:
695 D = dj * cdp.align_tensors[cdp.align_ids.index(align_id)].A_diag
696 Da = 1.0/3.0 * (D[2, 2] - (D[0, 0]+D[1, 1])/2.0)
697 Dr = 1.0/3.0 * (D[0, 0] - D[1, 1])
698 if Da == 0:
699 R = nan
700 else:
701 R = Dr / Da
702 norm = 2.0 * (Da)**2 * (4.0 + 3.0*R**2)/5.0
703 if Da == 0.0:
704 norm = 1e-15
705
706
707 cdp.q_factors_rdc[align_id] = sqrt(sse / N / norm)
708
709 else:
710 cdp.q_factors_rdc[align_id] = 0.0
711
712
713 cdp.q_factors_rdc_norm2[align_id] = sqrt(sse / D2_sum)
714
715
716 cdp.q_rdc = 0.0
717 cdp.q_rdc_norm2 = 0.0
718 for id in cdp.q_factors_rdc:
719 cdp.q_rdc = cdp.q_rdc + cdp.q_factors_rdc[id]**2
720 for id in cdp.q_factors_rdc_norm2:
721 cdp.q_rdc_norm2 = cdp.q_rdc_norm2 + cdp.q_factors_rdc_norm2[id]**2
722 cdp.q_rdc = sqrt(cdp.q_rdc / len(cdp.q_factors_rdc))
723 cdp.q_rdc_norm2 = sqrt(cdp.q_rdc_norm2 / len(cdp.q_factors_rdc_norm2))
724
725
726 -def read(align_id=None, file=None, dir=None, file_data=None, data_type='D', spin_id1_col=None, spin_id2_col=None, data_col=None, error_col=None, sep=None, neg_g_corr=False, absolute=False):
727 """Read the RDC data from file.
728
729 @keyword align_id: The alignment tensor ID string.
730 @type align_id: str
731 @keyword file: The name of the file to open.
732 @type file: str
733 @keyword dir: The directory containing the file (defaults to the current directory if None).
734 @type dir: str or None
735 @keyword file_data: An alternative to opening a file, if the data already exists in the correct format. The format is a list of lists where the first index corresponds to the row and the second the column.
736 @type file_data: list of lists
737 @keyword data_type: A string which is set to 'D' means that the splitting in the aligned sample was assumed to be J + D, or if set to '2D' then the splitting was taken as J + 2D. If set to 'T', then the data will be marked as being J+D values.
738 @keyword spin_id1_col: The column containing the spin ID strings of the first spin.
739 @type spin_id1_col: int
740 @keyword spin_id2_col: The column containing the spin ID strings of the second spin.
741 @type spin_id2_col: int
742 @keyword data_col: The column containing the RDC data in Hz.
743 @type data_col: int or None
744 @keyword error_col: The column containing the RDC errors.
745 @type error_col: int or None
746 @keyword sep: The column separator which, if None, defaults to whitespace.
747 @type sep: str or None
748 @keyword neg_g_corr: A flag which is used to correct for the negative gyromagnetic ratio of 15N. If True, a sign inversion will be applied to all RDC values to be loaded.
749 @type neg_g_corr: bool
750 @keyword absolute: A flag which if True indicates that the RDCs to load are signless. All RDCs will then be converted to positive values.
751 @type absolute: bool
752 """
753
754
755 check_pipe_setup(sequence=True)
756
757
758 if data_col == None and error_col == None:
759 raise RelaxError("One of either the data or error column must be supplied.")
760
761
762 rdc_types = ['D', '2D', 'T']
763 if data_type not in rdc_types:
764 raise RelaxError("The RDC data type '%s' must be one of %s." % (data_type, rdc_types))
765
766
767
768
769
770 file_data = extract_data(file, dir, sep=sep)
771 file_data = strip(file_data, comments=True)
772
773
774 data = []
775 for line in file_data:
776
777 if spin_id1_col > len(line):
778 warn(RelaxWarning("The data %s is invalid, no first spin ID column can be found." % line))
779 continue
780 if spin_id2_col > len(line):
781 warn(RelaxWarning("The data %s is invalid, no second spin ID column can be found." % line))
782 continue
783 if data_col and data_col > len(line):
784 warn(RelaxWarning("The data %s is invalid, no data column can be found." % line))
785 continue
786 if error_col and error_col > len(line):
787 warn(RelaxWarning("The data %s is invalid, no error column can be found." % line))
788 continue
789
790
791 spin_id1 = line[spin_id1_col-1]
792 spin_id2 = line[spin_id2_col-1]
793 value = None
794 if data_col:
795 value = line[data_col-1]
796 error = None
797 if error_col:
798 error = line[error_col-1]
799
800
801 if spin_id1[0] in ["\"", "\'"]:
802 spin_id1 = eval(spin_id1)
803 if spin_id2[0] in ["\"", "\'"]:
804 spin_id2 = eval(spin_id2)
805
806
807 if value == 'None':
808 value = None
809 if value != None:
810 try:
811 value = float(value)
812 except ValueError:
813 warn(RelaxWarning("The RDC value of the line %s is invalid." % line))
814 continue
815
816
817 if error == 'None':
818 error = None
819 if error != None:
820 try:
821 error = float(error)
822 except ValueError:
823 warn(RelaxWarning("The error value of the line %s is invalid." % line))
824 continue
825
826
827 spin1 = return_spin(spin_id1)
828 spin2 = return_spin(spin_id2)
829
830
831 if not spin1:
832 warn(RelaxWarning("The spin ID '%s' cannot be found in the current data pipe, skipping the data %s." % (spin_id1, line)))
833 continue
834 if not spin2:
835 warn(RelaxWarning("The spin ID '%s' cannot be found in the current data pipe, skipping the data %s." % (spin_id2, line)))
836 continue
837
838
839 interatom = return_interatom(spin_id1, spin_id2)
840
841
842 if interatom == None:
843 interatom = create_interatom(spin_id1=spin_id1, spin_id2=spin_id2)
844
845
846 if error == 0.0:
847 interatom.select = False
848 warn(RelaxWarning("An error value of zero has been encountered, deselecting the interatomic container between spin '%s' and '%s'." % (spin_id1, spin_id2)))
849 continue
850
851
852 if not hasattr(interatom, 'rdc_data_types'):
853 interatom.rdc_data_types = {}
854 if not align_id in interatom.rdc_data_types:
855 interatom.rdc_data_types[align_id] = data_type
856
857
858 if data_col:
859
860 value = convert(value, data_type, align_id, to_intern=True)
861
862
863 if neg_g_corr and value != None:
864 value = -value
865
866
867 if absolute:
868
869 value = abs(value)
870
871
872 if not hasattr(interatom, 'rdc'):
873 interatom.rdc = {}
874
875
876 interatom.rdc[align_id] = value
877
878
879 if not hasattr(interatom, 'absolute_rdc'):
880 interatom.absolute_rdc = {}
881 interatom.absolute_rdc[align_id] = absolute
882
883
884 if error_col:
885
886 error = convert(error, data_type, align_id, to_intern=True)
887
888
889 if not hasattr(interatom, 'rdc_err'):
890 interatom.rdc_err = {}
891
892
893 interatom.rdc_err[align_id] = error
894
895
896 data.append([spin_id1, spin_id2])
897 if is_float(value):
898 data[-1].append("%20.15f" % value)
899 else:
900 data[-1].append("%20s" % value)
901 if is_float(error):
902 data[-1].append("%20.15f" % error)
903 else:
904 data[-1].append("%20s" % error)
905
906
907 if not len(data):
908 raise RelaxError("No RDC data could be extracted.")
909
910
911 print("The following RDCs have been loaded into the relax data store:\n")
912 write_data(out=sys.stdout, headings=["Spin_ID1", "Spin_ID2", "Value", "Error"], data=data)
913
914
915 if not hasattr(cdp, 'align_ids'):
916 cdp.align_ids = []
917 if not hasattr(cdp, 'rdc_ids'):
918 cdp.rdc_ids = []
919
920
921 if align_id not in cdp.align_ids:
922 cdp.align_ids.append(align_id)
923 if align_id not in cdp.rdc_ids:
924 cdp.rdc_ids.append(align_id)
925
926
928 """Set up the data structures for optimisation using RDCs as base data sets.
929
930 @keyword sim_index: The index of the simulation to optimise. This should be None if normal optimisation is desired.
931 @type sim_index: None or int
932 @return: The assembled data structures for using RDCs as the base data for optimisation. These include:
933 - rdc, the RDC values.
934 - rdc_err, the RDC errors.
935 - rdc_weight, the RDC weights.
936 - vectors, the interatomic vectors (pseudo-atom dependent).
937 - rdc_const, the dipolar constants (pseudo-atom dependent).
938 - absolute, the absolute value flags (as 1's and 0's).
939 - T_flags, the flags for T = J+D type data (as 1's and 0's).
940 - j_couplings, the J coupling values if the RDC data type is set to T = J+D.
941 - pseudo_flags, the list of flags indicating if the interatomic data contains a pseudo-atom (as 1's and 0's).
942 @rtype: tuple of (numpy rank-2 float64 array, numpy rank-2 float64 array, numpy rank-2 float64 array, list of numpy rank-3 float64 arrays, list of lists of floats, numpy rank-2 int32 array, numpy rank-2 int32 array, numpy rank-2 float64 array, numpy rank-1 int32 array)
943 """
944
945
946 setup_pseudoatom_rdc()
947
948
949 rdc = []
950 rdc_err = []
951 rdc_weight = []
952 unit_vect = []
953 rdc_const = []
954 absolute = []
955 T_flags = []
956 j_couplings = []
957 pseudo_flags = []
958
959
960 for interatom in interatomic_loop():
961
962 spin1 = return_spin(interatom.spin_id1)
963 spin2 = return_spin(interatom.spin_id2)
964
965
966 if not check_rdcs(interatom):
967 continue
968
969
970 g1 = return_gyromagnetic_ratio(spin1.isotope)
971 g2 = return_gyromagnetic_ratio(spin2.isotope)
972
973
974 if is_pseudoatom(spin1) and is_pseudoatom(spin2):
975 raise RelaxError("Support for both spins being in a dipole pair being pseudo-atoms is not implemented yet.")
976 if is_pseudoatom(spin1) or is_pseudoatom(spin2):
977
978 pseudo_flags.append(1)
979
980
981 if is_pseudoatom(spin1):
982 pseudospin = spin1
983 base_spin = spin2
984 pseudospin_id = interatom.spin_id1
985 base_spin_id = interatom.spin_id2
986 else:
987 pseudospin = spin2
988 base_spin = spin1
989 pseudospin_id = interatom.spin_id2
990 base_spin_id = interatom.spin_id1
991
992
993 pseudo_unit_vect = []
994 pseudo_rdc_const = []
995 for spin, spin_id in pseudoatom_loop(pseudospin, return_id=True):
996
997 pseudo_interatom = return_interatom(spin_id1=spin_id, spin_id2=base_spin_id)
998
999
1000 if pseudo_interatom == None:
1001 raise RelaxError("The interatomic data container between the spins '%s' and '%s' for the pseudo-atom '%s' is not defined." % (base_spin_id, spin_id, pseudospin_id))
1002
1003
1004 if is_float(interatom.vector[0]):
1005 pseudo_unit_vect.append([pseudo_interatom.vector])
1006 else:
1007 pseudo_unit_vect.append(pseudo_interatom.vector)
1008
1009
1010 pseudo_rdc_const.append(3.0/(2.0*pi) * dipolar_constant(g1, g2, pseudo_interatom.r))
1011
1012
1013 pseudo_unit_vect = transpose(array(pseudo_unit_vect, float64), (1, 0, 2))
1014
1015
1016 unit_vect.append(pseudo_unit_vect)
1017 rdc_const.append(pseudo_rdc_const)
1018
1019
1020 else:
1021
1022 pseudo_flags.append(0)
1023
1024
1025 if is_float(interatom.vector[0]):
1026 unit_vect.append([interatom.vector])
1027 else:
1028 unit_vect.append(interatom.vector)
1029
1030
1031 rdc_const.append(3.0/(2.0*pi) * dipolar_constant(g1, g2, interatom.r))
1032
1033
1034 if opt_uses_j_couplings():
1035 j_couplings.append(interatom.j_coupling)
1036
1037
1038 num = None
1039 for rdc_index in range(len(unit_vect)):
1040
1041 unit_vect[rdc_index] = array(unit_vect[rdc_index], float64)
1042
1043
1044 if num == None:
1045 if unit_vect[rdc_index] != None:
1046 num = len(unit_vect[rdc_index])
1047 continue
1048
1049
1050 if unit_vect[rdc_index] != None and len(unit_vect[rdc_index]) != num:
1051 raise RelaxError("The number of interatomic vectors for all no match:\n%s" % unit_vect[rdc_index])
1052
1053
1054 if num == None:
1055 raise RelaxError("No interatomic vectors could be found.")
1056
1057
1058 for i in range(len(unit_vect)):
1059 if unit_vect[i] == None:
1060 unit_vect[i] = [[None, None, None]]*num
1061
1062
1063 for i in range(len(cdp.align_ids)):
1064
1065 align_id = cdp.align_ids[i]
1066
1067
1068 if not opt_uses_align_data(align_id):
1069 continue
1070
1071
1072 rdc.append([])
1073 rdc_err.append([])
1074 rdc_weight.append([])
1075 absolute.append([])
1076 T_flags.append([])
1077
1078
1079 for interatom in interatomic_loop():
1080
1081 spin1 = return_spin(interatom.spin_id1)
1082 spin2 = return_spin(interatom.spin_id2)
1083
1084
1085 if not check_rdcs(interatom):
1086 continue
1087
1088
1089 if align_id in interatom.rdc_data_types and interatom.rdc_data_types[align_id] == 'T':
1090 T_flags[-1].append(True)
1091 else:
1092 T_flags[-1].append(False)
1093
1094
1095 if T_flags[-1][-1] and not hasattr(interatom, 'j_coupling'):
1096 continue
1097
1098
1099 value = None
1100 error = None
1101
1102
1103 if align_id in interatom.rdc.keys():
1104
1105 if sim_index != None:
1106 value = interatom.rdc_sim[align_id][sim_index]
1107 else:
1108 value = interatom.rdc[align_id]
1109
1110
1111 if hasattr(interatom, 'rdc_err') and align_id in interatom.rdc_err.keys():
1112
1113 if T_flags[-1][-1]:
1114 error = sqrt(interatom.rdc_err[align_id]**2 + interatom.j_coupling_err**2)
1115
1116
1117 else:
1118 error = interatom.rdc_err[align_id]
1119
1120
1121 rdc[-1].append(value)
1122
1123
1124 rdc_err[-1].append(error)
1125
1126
1127 if hasattr(interatom, 'rdc_weight') and align_id in interatom.rdc_weight.keys():
1128 rdc_weight[-1].append(interatom.rdc_weight[align_id])
1129 else:
1130 rdc_weight[-1].append(1.0)
1131
1132
1133 if hasattr(interatom, 'absolute_rdc') and align_id in interatom.absolute_rdc.keys():
1134 absolute[-1].append(interatom.absolute_rdc[align_id])
1135 else:
1136 absolute[-1].append(False)
1137
1138
1139 rdc = array(rdc, float64)
1140 rdc_err = array(rdc_err, float64)
1141 rdc_weight = array(rdc_weight, float64)
1142 absolute = array(absolute, int32)
1143 T_flags = array(T_flags, int32)
1144 if not opt_uses_j_couplings():
1145 j_couplings = None
1146 pseudo_flags = array(pseudo_flags, int32)
1147
1148
1149 return rdc, rdc_err, rdc_weight, unit_vect, rdc_const, absolute, T_flags, j_couplings, pseudo_flags
1150
1151
1152 -def set_errors(align_id=None, spin_id1=None, spin_id2=None, sd=None):
1153 """Set the RDC errors if not already present.
1154
1155 @keyword align_id: The optional alignment tensor ID string.
1156 @type align_id: str
1157 @keyword spin_id1: The optional spin ID string of the first spin.
1158 @type spin_id1: None or str
1159 @keyword spin_id2: The optional spin ID string of the second spin.
1160 @type spin_id2: None or str
1161 @keyword sd: The RDC standard deviation in Hz.
1162 @type sd: float or int.
1163 """
1164
1165
1166 check_pipe_setup(sequence=True, rdc_id=align_id, rdc=True)
1167
1168
1169 if align_id:
1170 align_ids = [align_id]
1171 else:
1172 align_ids = cdp.rdc_ids
1173
1174
1175 for interatom in interatomic_loop(selection1=spin_id1, selection2=spin_id2):
1176
1177 if not hasattr(interatom, 'rdc_err'):
1178 interatom.rdc_err = {}
1179
1180
1181 for id in align_ids:
1182 interatom.rdc_err[id] = sd
1183
1184
1186 """Make sure that the interatom system is properly set up for pseudo-atoms and RDCs.
1187
1188 Interatomic data containers between the non-pseudo-atom and the pseudo-atom members will be deselected.
1189 """
1190
1191
1192 for interatom in interatomic_loop():
1193
1194 spin1 = return_spin(interatom.spin_id1)
1195 spin2 = return_spin(interatom.spin_id2)
1196
1197
1198 flag1 = is_pseudoatom(spin1)
1199 flag2 = is_pseudoatom(spin2)
1200
1201
1202 if not (flag1 or flag2):
1203 continue
1204
1205
1206 if flag1 and flag2:
1207 warn(RelaxWarning("Support for both spins being in a dipole pair being pseudo-atoms is not implemented yet, deselecting the interatomic data container for the spin pair '%s' and '%s'." % (interatom.spin_id1, interatom.spin_id2)))
1208 interatom.select = False
1209
1210
1211 pseudospin = spin1
1212 base_spin_id = interatom.spin_id2
1213 pseudospin_id = interatom.spin_id1
1214 if flag2:
1215 pseudospin = spin2
1216 base_spin_id = interatom.spin_id1
1217 pseudospin_id = interatom.spin_id2
1218
1219
1220 for spin, spin_id in pseudoatom_loop(pseudospin, return_id=True):
1221
1222 pseudo_interatom = return_interatom(spin_id1=spin_id, spin_id2=base_spin_id)
1223
1224
1225 if pseudo_interatom.select:
1226 warn(RelaxWarning("Deselecting the interatomic data container for the spin pair '%s' and '%s' as it is part of the pseudo-atom system of the spin pair '%s' and '%s'." % (pseudo_interatom.spin_id1, pseudo_interatom.spin_id2, base_spin_id, pseudospin_id)))
1227 pseudo_interatom.select = False
1228
1229
1230 -def weight(align_id=None, spin_id=None, weight=1.0):
1231 """Set optimisation weights on the RDC data.
1232
1233 @keyword align_id: The alignment tensor ID string.
1234 @type align_id: str
1235 @keyword spin_id: The spin ID string.
1236 @type spin_id: None or str
1237 @keyword weight: The optimisation weight. The higher the value, the more importance the RDC will have.
1238 @type weight: float or int.
1239 """
1240
1241
1242 check_pipe_setup(sequence=True, rdc_id=align_id, rdc=True)
1243
1244
1245 for interatom in interatomic_loop():
1246
1247 if not hasattr(interatom, 'rdc_weight'):
1248 interatom.rdc_weight = {}
1249
1250
1251 interatom.rdc_weight[align_id] = weight
1252
1253
1254 -def write(align_id=None, file=None, dir=None, bc=False, force=False):
1255 """Display the RDC data corresponding to the alignment ID.
1256
1257 @keyword align_id: The alignment tensor ID string.
1258 @type align_id: str
1259 @keyword file: The file name or object to write to.
1260 @type file: str or file object
1261 @keyword dir: The name of the directory to place the file into (defaults to the current directory).
1262 @type dir: str
1263 @keyword bc: The back-calculation flag which if True will cause the back-calculated rather than measured data to be written.
1264 @type bc: bool
1265 @keyword force: A flag which if True will cause any pre-existing file to be overwritten.
1266 @type force: bool
1267 """
1268
1269
1270 check_pipe_setup(sequence=True, rdc_id=align_id, rdc=True)
1271
1272
1273 file = open_write_file(file, dir, force)
1274
1275
1276 data = []
1277 for interatom in interatomic_loop():
1278
1279 if not interatom.select:
1280 continue
1281
1282
1283 if not bc and (not hasattr(interatom, 'rdc') or align_id not in interatom.rdc.keys()):
1284 continue
1285 elif bc and (not hasattr(interatom, 'rdc_bc') or align_id not in interatom.rdc_bc.keys()):
1286 continue
1287
1288
1289 data.append([])
1290 data[-1].append(repr(interatom.spin_id1))
1291 data[-1].append(repr(interatom.spin_id2))
1292
1293
1294 data_type = None
1295 if hasattr(interatom, 'rdc_data_types'):
1296 data_type = interatom.rdc_data_types[align_id]
1297
1298
1299 if bc:
1300 data[-1].append(repr(convert(interatom.rdc_bc[align_id], data_type, align_id)))
1301 else:
1302 data[-1].append(repr(convert(interatom.rdc[align_id], data_type, align_id)))
1303
1304
1305 if hasattr(interatom, 'rdc_err') and align_id in interatom.rdc_err.keys():
1306 data[-1].append(repr(convert(interatom.rdc_err[align_id], data_type, align_id)))
1307 else:
1308 data[-1].append(repr(None))
1309
1310
1311 write_data(out=file, headings=["Spin_ID1", "Spin_ID2", "RDCs", "RDC_error"], data=data)
1312