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, 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 file: The file name or object to write to.
384 @type file: str or file object
385 @keyword dir: The name of the directory to place the file into (defaults to the current directory).
386 @type dir: str
387 @keyword force: A flag which if True will cause any pre-existing file to be overwritten.
388 @type force: bool
389 """
390
391
392 check_pipe_setup(sequence=True)
393
394
395 if not hasattr(cdp, 'rdc_ids') or not cdp.rdc_ids:
396 warn(RelaxWarning("No RDC data exists, skipping file creation."))
397 return
398
399
400 file = open_write_file(file, dir, force)
401
402
403 data = []
404
405
406 data.append([[-100, -100, 0], [100, 100, 0]])
407
408
409 for align_id in cdp.rdc_ids:
410
411 data.append([])
412
413
414 err_flag = False
415 for interatom in interatomic_loop():
416
417 if hasattr(interatom, 'rdc_err') and align_id in interatom.rdc_err.keys():
418 err_flag = True
419 break
420
421
422 for interatom in interatomic_loop():
423
424 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():
425 continue
426
427
428 rdc_bc = convert(interatom.rdc_bc[align_id], interatom.rdc_data_types[align_id], align_id)
429 rdc = convert(interatom.rdc[align_id], interatom.rdc_data_types[align_id], align_id)
430 if hasattr(interatom, 'rdc_data_types') and align_id in interatom.rdc_data_types and interatom.rdc_data_types[align_id] == 'T':
431 rdc_bc -= interatom.j_coupling
432 rdc -= interatom.j_coupling
433 data[-1].append([rdc_bc, rdc])
434
435
436 if err_flag:
437 if hasattr(interatom, 'rdc_err') and align_id in interatom.rdc_err.keys():
438 data[-1][-1].append(convert(interatom.rdc_err[align_id], interatom.rdc_data_types[align_id], align_id))
439 else:
440 data[-1][-1].append(None)
441
442
443 data[-1][-1].append("%s-%s" % (interatom.spin_id1, interatom.spin_id2))
444
445
446 size = len(data)
447
448
449 data = [data]
450
451
452 if err_flag:
453 graph_type = 'xydy'
454 else:
455 graph_type = 'xy'
456
457
458 if format == 'grace':
459
460 grace.write_xy_header(file=file, title="RDC correlation plot", sets=[size], set_names=[[None]+cdp.rdc_ids], linestyle=[[2]+[0]*size], data_type=['rdc_bc', 'rdc'], legend_pos=[[1, 0.5]])
461
462
463 grace.write_xy_data(data=data, file=file, graph_type=graph_type)
464
465
467 """Delete the RDC data corresponding to the alignment ID.
468
469 @keyword align_id: The alignment tensor ID string. If not specified, all data will be deleted.
470 @type align_id: str or None
471 """
472
473
474 check_pipe_setup(sequence=True, rdc_id=align_id, rdc=True)
475
476
477 if not align_id:
478 ids = deepcopy(cdp.rdc_ids)
479 else:
480 ids = [align_id]
481
482
483 for id in ids:
484
485 cdp.rdc_ids.pop(cdp.rdc_ids.index(id))
486
487
488 for interatom in interatomic_loop():
489
490 if hasattr(interatom, 'rdc') and id in interatom.rdc:
491 interatom.rdc.pop(id)
492
493
494 if hasattr(interatom, 'rdc_err') and id in interatom.rdc_err:
495 interatom.rdc_err.pop(id)
496
497
498 if hasattr(interatom, 'rdc_data_types') and id in interatom.rdc_data_types:
499 interatom.rdc_data_types.pop(id)
500
501
502 if not hasattr(cdp, 'pcs_ids') or id not in cdp.pcs_ids:
503 cdp.align_ids.pop(cdp.align_ids.index(id))
504
505
506 -def display(align_id=None, bc=False):
507 """Display the RDC data corresponding to the alignment ID.
508
509 @keyword align_id: The alignment tensor ID string.
510 @type align_id: str
511 @keyword bc: The back-calculation flag which if True will cause the back-calculated rather than measured data to be displayed.
512 @type bc: bool
513 """
514
515
516 check_pipe_setup(sequence=True, rdc_id=align_id, rdc=True)
517
518
519 write(align_id=align_id, file=sys.stdout, bc=bc)
520
521
523 """Determine of J couplings are needed for optimisation.
524
525 @return: True if J couplings are required, False otherwise.
526 @rtype: bool
527 """
528
529
530 for align_id in cdp.align_ids:
531 for interatom in interatomic_loop():
532 if hasattr(interatom, 'rdc_data_types') and align_id in interatom.rdc_data_types and interatom.rdc_data_types[align_id] == 'T':
533 return True
534
535
536 return False
537
538
540 """Determine if the RDC data for the given alignment ID is needed for optimisation.
541
542 @param align_id: The alignment ID string.
543 @type align_id: str
544 @return: True if the RDC data is to be used for optimisation, False otherwise.
545 @rtype: bool
546 """
547
548
549 if not hasattr(cdp, 'rdc_ids'):
550 return False
551
552
553 if align_id not in cdp.rdc_ids:
554 return False
555
556
557 tensor_flag = opt_uses_tensor(get_tensor_object(align_id))
558
559
560 pos_flag = False
561 if hasattr(cdp, 'paramag_centre_fixed') and not cdp.paramag_centre_fixed:
562 pos_flag = True
563
564
565 prob_flag = False
566 if cdp.model == 'population':
567 prob_flag = True
568
569
570 if not tensor_flag and not pos_flag and not prob_flag:
571 return False
572
573
574 return True
575
576
578 """Calculate the Q-factors for the RDC data.
579
580 @keyword spin_id: The spin ID string used to restrict the Q-factor calculation to a subset of all spins.
581 @type spin_id: None or str
582 """
583
584
585 check_pipe_setup(sequence=True)
586
587
588 if not hasattr(cdp, 'rdc_ids') or not len(cdp.rdc_ids):
589 warn(RelaxWarning("No RDC data exists, Q factors cannot be calculated."))
590 return
591
592
593 cdp.q_factors_rdc = {}
594 cdp.q_factors_rdc_norm2 = {}
595
596
597 for align_id in cdp.rdc_ids:
598
599 D2_sum = 0.0
600 sse = 0.0
601
602
603 dj = None
604 N = 0
605 interatom_count = 0
606 rdc_data = False
607 rdc_bc_data = False
608 norm2_flag = True
609 for interatom in interatomic_loop():
610
611 interatom_count += 1
612
613
614 if hasattr(interatom, 'rdc') and align_id in interatom.rdc:
615 rdc_data = True
616 if hasattr(interatom, 'rdc_bc') and align_id in interatom.rdc_bc:
617 rdc_bc_data = True
618 j_flag = False
619 if hasattr(interatom, 'rdc_data_types') and align_id in interatom.rdc_data_types and interatom.rdc_data_types[align_id] == 'T':
620 j_flag = True
621 if not hasattr(interatom, 'j_coupling'):
622 raise RelaxNoJError
623
624
625 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:
626 continue
627
628
629 spin1 = return_spin(interatom.spin_id1)
630 spin2 = return_spin(interatom.spin_id2)
631
632
633 sse = sse + (interatom.rdc[align_id] - interatom.rdc_bc[align_id])**2
634
635
636 if j_flag:
637 D2_sum = D2_sum + (interatom.rdc[align_id] - interatom.j_coupling)**2
638 else:
639 D2_sum = D2_sum + interatom.rdc[align_id]**2
640
641
642 g1 = return_gyromagnetic_ratio(spin1.isotope)
643 g2 = return_gyromagnetic_ratio(spin2.isotope)
644
645
646 if norm2_flag and (is_pseudoatom(spin1) or is_pseudoatom(spin2)):
647 warn(RelaxWarning("Pseudo-atoms are present, skipping the Q factor normalised with 2Da^2(4 + 3R)/5."))
648 norm2_flag = False
649
650
651 if norm2_flag:
652 dj_new = 3.0/(2.0*pi) * dipolar_constant(g1, g2, interatom.r)
653 if dj != None and dj_new != dj:
654 warn(RelaxWarning("The dipolar constant is not the same for all RDCs, skipping the Q factor normalised with 2Da^2(4 + 3R)/5."))
655 norm2_flag = False
656 else:
657 dj = dj_new
658
659
660 N = N + 1
661
662
663 if not interatom_count:
664 warn(RelaxWarning("No interatomic data containers have been used in the calculation, skipping the RDC Q factor calculation."))
665 return
666 if not rdc_data:
667 warn(RelaxWarning("No RDC data can be found for the alignment ID '%s', skipping the RDC Q factor calculation for this alignment." % align_id))
668 continue
669 if not rdc_bc_data:
670 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))
671 continue
672
673
674 if norm2_flag:
675 D = dj * cdp.align_tensors[cdp.align_ids.index(align_id)].A_diag
676 Da = 1.0/3.0 * (D[2, 2] - (D[0, 0]+D[1, 1])/2.0)
677 Dr = 1.0/3.0 * (D[0, 0] - D[1, 1])
678 if Da == 0:
679 R = nan
680 else:
681 R = Dr / Da
682 norm = 2.0 * (Da)**2 * (4.0 + 3.0*R**2)/5.0
683 if Da == 0.0:
684 norm = 1e-15
685
686
687 cdp.q_factors_rdc[align_id] = sqrt(sse / N / norm)
688
689 else:
690 cdp.q_factors_rdc[align_id] = 0.0
691
692
693 cdp.q_factors_rdc_norm2[align_id] = sqrt(sse / D2_sum)
694
695
696 cdp.q_rdc = 0.0
697 cdp.q_rdc_norm2 = 0.0
698 for id in cdp.q_factors_rdc:
699 cdp.q_rdc = cdp.q_rdc + cdp.q_factors_rdc[id]**2
700 for id in cdp.q_factors_rdc_norm2:
701 cdp.q_rdc_norm2 = cdp.q_rdc_norm2 + cdp.q_factors_rdc_norm2[id]**2
702 cdp.q_rdc = sqrt(cdp.q_rdc / len(cdp.q_factors_rdc))
703 cdp.q_rdc_norm2 = sqrt(cdp.q_rdc_norm2 / len(cdp.q_factors_rdc_norm2))
704
705
706 -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):
707 """Read the RDC data from file.
708
709 @keyword align_id: The alignment tensor ID string.
710 @type align_id: str
711 @keyword file: The name of the file to open.
712 @type file: str
713 @keyword dir: The directory containing the file (defaults to the current directory if None).
714 @type dir: str or None
715 @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.
716 @type file_data: list of lists
717 @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.
718 @keyword spin_id1_col: The column containing the spin ID strings of the first spin.
719 @type spin_id1_col: int
720 @keyword spin_id2_col: The column containing the spin ID strings of the second spin.
721 @type spin_id2_col: int
722 @keyword data_col: The column containing the RDC data in Hz.
723 @type data_col: int or None
724 @keyword error_col: The column containing the RDC errors.
725 @type error_col: int or None
726 @keyword sep: The column separator which, if None, defaults to whitespace.
727 @type sep: str or None
728 @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.
729 @type neg_g_corr: bool
730 @keyword absolute: A flag which if True indicates that the RDCs to load are signless. All RDCs will then be converted to positive values.
731 @type absolute: bool
732 """
733
734
735 check_pipe_setup(sequence=True)
736
737
738 if data_col == None and error_col == None:
739 raise RelaxError("One of either the data or error column must be supplied.")
740
741
742 rdc_types = ['D', '2D', 'T']
743 if data_type not in rdc_types:
744 raise RelaxError("The RDC data type '%s' must be one of %s." % (data_type, rdc_types))
745
746
747
748
749
750 file_data = extract_data(file, dir, sep=sep)
751 file_data = strip(file_data, comments=True)
752
753
754 data = []
755 for line in file_data:
756
757 if spin_id1_col > len(line):
758 warn(RelaxWarning("The data %s is invalid, no first spin ID column can be found." % line))
759 continue
760 if spin_id2_col > len(line):
761 warn(RelaxWarning("The data %s is invalid, no second spin ID column can be found." % line))
762 continue
763 if data_col and data_col > len(line):
764 warn(RelaxWarning("The data %s is invalid, no data column can be found." % line))
765 continue
766 if error_col and error_col > len(line):
767 warn(RelaxWarning("The data %s is invalid, no error column can be found." % line))
768 continue
769
770
771 spin_id1 = line[spin_id1_col-1]
772 spin_id2 = line[spin_id2_col-1]
773 value = None
774 if data_col:
775 value = line[data_col-1]
776 error = None
777 if error_col:
778 error = line[error_col-1]
779
780
781 if spin_id1[0] in ["\"", "\'"]:
782 spin_id1 = eval(spin_id1)
783 if spin_id2[0] in ["\"", "\'"]:
784 spin_id2 = eval(spin_id2)
785
786
787 if value == 'None':
788 value = None
789 if value != None:
790 try:
791 value = float(value)
792 except ValueError:
793 warn(RelaxWarning("The RDC value of the line %s is invalid." % line))
794 continue
795
796
797 if error == 'None':
798 error = None
799 if error != None:
800 try:
801 error = float(error)
802 except ValueError:
803 warn(RelaxWarning("The error value of the line %s is invalid." % line))
804 continue
805
806
807 spin1 = return_spin(spin_id1)
808 spin2 = return_spin(spin_id2)
809
810
811 if not spin1:
812 warn(RelaxWarning("The spin ID '%s' cannot be found in the current data pipe, skipping the data %s." % (spin_id1, line)))
813 continue
814 if not spin2:
815 warn(RelaxWarning("The spin ID '%s' cannot be found in the current data pipe, skipping the data %s." % (spin_id2, line)))
816 continue
817
818
819 interatom = return_interatom(spin_id1, spin_id2)
820
821
822 if interatom == None:
823 interatom = create_interatom(spin_id1=spin_id1, spin_id2=spin_id2)
824
825
826 if error == 0.0:
827 interatom.select = False
828 warn(RelaxWarning("An error value of zero has been encountered, deselecting the interatomic container between spin '%s' and '%s'." % (spin_id1, spin_id2)))
829 continue
830
831
832 if not hasattr(interatom, 'rdc_data_types'):
833 interatom.rdc_data_types = {}
834 if not align_id in interatom.rdc_data_types:
835 interatom.rdc_data_types[align_id] = data_type
836
837
838 if data_col:
839
840 value = convert(value, data_type, align_id, to_intern=True)
841
842
843 if neg_g_corr and value != None:
844 value = -value
845
846
847 if absolute:
848
849 value = abs(value)
850
851
852 if not hasattr(interatom, 'rdc'):
853 interatom.rdc = {}
854
855
856 interatom.rdc[align_id] = value
857
858
859 if not hasattr(interatom, 'absolute_rdc'):
860 interatom.absolute_rdc = {}
861 interatom.absolute_rdc[align_id] = absolute
862
863
864 if error_col:
865
866 error = convert(error, data_type, align_id, to_intern=True)
867
868
869 if not hasattr(interatom, 'rdc_err'):
870 interatom.rdc_err = {}
871
872
873 interatom.rdc_err[align_id] = error
874
875
876 data.append([spin_id1, spin_id2])
877 if is_float(value):
878 data[-1].append("%20.15f" % value)
879 else:
880 data[-1].append("%20s" % value)
881 if is_float(error):
882 data[-1].append("%20.15f" % error)
883 else:
884 data[-1].append("%20s" % error)
885
886
887 if not len(data):
888 raise RelaxError("No RDC data could be extracted.")
889
890
891 print("The following RDCs have been loaded into the relax data store:\n")
892 write_data(out=sys.stdout, headings=["Spin_ID1", "Spin_ID2", "Value", "Error"], data=data)
893
894
895 if not hasattr(cdp, 'align_ids'):
896 cdp.align_ids = []
897 if not hasattr(cdp, 'rdc_ids'):
898 cdp.rdc_ids = []
899
900
901 if align_id not in cdp.align_ids:
902 cdp.align_ids.append(align_id)
903 if align_id not in cdp.rdc_ids:
904 cdp.rdc_ids.append(align_id)
905
906
908 """Set up the data structures for optimisation using RDCs as base data sets.
909
910 @keyword sim_index: The index of the simulation to optimise. This should be None if normal optimisation is desired.
911 @type sim_index: None or int
912 @return: The assembled data structures for using RDCs as the base data for optimisation. These include:
913 - rdc, the RDC values.
914 - rdc_err, the RDC errors.
915 - rdc_weight, the RDC weights.
916 - vectors, the interatomic vectors (pseudo-atom dependent).
917 - rdc_const, the dipolar constants (pseudo-atom dependent).
918 - absolute, the absolute value flags (as 1's and 0's).
919 - T_flags, the flags for T = J+D type data (as 1's and 0's).
920 - j_couplings, the J coupling values if the RDC data type is set to T = J+D.
921 - pseudo_flags, the list of flags indicating if the interatomic data contains a pseudo-atom (as 1's and 0's).
922 @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)
923 """
924
925
926 setup_pseudoatom_rdc()
927
928
929 rdc = []
930 rdc_err = []
931 rdc_weight = []
932 unit_vect = []
933 rdc_const = []
934 absolute = []
935 T_flags = []
936 j_couplings = []
937 pseudo_flags = []
938
939
940 for interatom in interatomic_loop():
941
942 spin1 = return_spin(interatom.spin_id1)
943 spin2 = return_spin(interatom.spin_id2)
944
945
946 if not check_rdcs(interatom):
947 continue
948
949
950 g1 = return_gyromagnetic_ratio(spin1.isotope)
951 g2 = return_gyromagnetic_ratio(spin2.isotope)
952
953
954 if is_pseudoatom(spin1) and is_pseudoatom(spin2):
955 raise RelaxError("Support for both spins being in a dipole pair being pseudo-atoms is not implemented yet.")
956 if is_pseudoatom(spin1) or is_pseudoatom(spin2):
957
958 pseudo_flags.append(1)
959
960
961 if is_pseudoatom(spin1):
962 pseudospin = spin1
963 base_spin = spin2
964 pseudospin_id = interatom.spin_id1
965 base_spin_id = interatom.spin_id2
966 else:
967 pseudospin = spin2
968 base_spin = spin1
969 pseudospin_id = interatom.spin_id2
970 base_spin_id = interatom.spin_id1
971
972
973 pseudo_unit_vect = []
974 pseudo_rdc_const = []
975 for spin, spin_id in pseudoatom_loop(pseudospin, return_id=True):
976
977 pseudo_interatom = return_interatom(spin_id1=spin_id, spin_id2=base_spin_id)
978
979
980 if pseudo_interatom == None:
981 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))
982
983
984 if is_float(interatom.vector[0]):
985 pseudo_unit_vect.append([pseudo_interatom.vector])
986 else:
987 pseudo_unit_vect.append(pseudo_interatom.vector)
988
989
990 pseudo_rdc_const.append(3.0/(2.0*pi) * dipolar_constant(g1, g2, pseudo_interatom.r))
991
992
993 pseudo_unit_vect = transpose(array(pseudo_unit_vect, float64), (1, 0, 2))
994
995
996 unit_vect.append(pseudo_unit_vect)
997 rdc_const.append(pseudo_rdc_const)
998
999
1000 else:
1001
1002 pseudo_flags.append(0)
1003
1004
1005 if is_float(interatom.vector[0]):
1006 unit_vect.append([interatom.vector])
1007 else:
1008 unit_vect.append(interatom.vector)
1009
1010
1011 rdc_const.append(3.0/(2.0*pi) * dipolar_constant(g1, g2, interatom.r))
1012
1013
1014 if opt_uses_j_couplings():
1015 j_couplings.append(interatom.j_coupling)
1016
1017
1018 num = None
1019 for rdc_index in range(len(unit_vect)):
1020
1021 unit_vect[rdc_index] = array(unit_vect[rdc_index], float64)
1022
1023
1024 if num == None:
1025 if unit_vect[rdc_index] != None:
1026 num = len(unit_vect[rdc_index])
1027 continue
1028
1029
1030 if unit_vect[rdc_index] != None and len(unit_vect[rdc_index]) != num:
1031 raise RelaxError("The number of interatomic vectors for all no match:\n%s" % unit_vect[rdc_index])
1032
1033
1034 if num == None:
1035 raise RelaxError("No interatomic vectors could be found.")
1036
1037
1038 for i in range(len(unit_vect)):
1039 if unit_vect[i] == None:
1040 unit_vect[i] = [[None, None, None]]*num
1041
1042
1043 for i in range(len(cdp.align_ids)):
1044
1045 align_id = cdp.align_ids[i]
1046
1047
1048 if not opt_uses_align_data(align_id):
1049 continue
1050
1051
1052 rdc.append([])
1053 rdc_err.append([])
1054 rdc_weight.append([])
1055 absolute.append([])
1056 T_flags.append([])
1057
1058
1059 for interatom in interatomic_loop():
1060
1061 spin1 = return_spin(interatom.spin_id1)
1062 spin2 = return_spin(interatom.spin_id2)
1063
1064
1065 if not check_rdcs(interatom):
1066 continue
1067
1068
1069 if align_id in interatom.rdc_data_types and interatom.rdc_data_types[align_id] == 'T':
1070 T_flags[-1].append(True)
1071 else:
1072 T_flags[-1].append(False)
1073
1074
1075 if T_flags[-1][-1] and not hasattr(interatom, 'j_coupling'):
1076 continue
1077
1078
1079 value = None
1080 error = None
1081
1082
1083 if align_id in interatom.rdc.keys():
1084
1085 if sim_index != None:
1086 value = interatom.rdc_sim[align_id][sim_index]
1087 else:
1088 value = interatom.rdc[align_id]
1089
1090
1091 if hasattr(interatom, 'rdc_err') and align_id in interatom.rdc_err.keys():
1092
1093 if T_flags[-1][-1]:
1094 error = sqrt(interatom.rdc_err[align_id]**2 + interatom.j_coupling_err**2)
1095
1096
1097 else:
1098 error = interatom.rdc_err[align_id]
1099
1100
1101 rdc[-1].append(value)
1102
1103
1104 rdc_err[-1].append(error)
1105
1106
1107 if hasattr(interatom, 'rdc_weight') and align_id in interatom.rdc_weight.keys():
1108 rdc_weight[-1].append(interatom.rdc_weight[align_id])
1109 else:
1110 rdc_weight[-1].append(1.0)
1111
1112
1113 if hasattr(interatom, 'absolute_rdc') and align_id in interatom.absolute_rdc.keys():
1114 absolute[-1].append(interatom.absolute_rdc[align_id])
1115 else:
1116 absolute[-1].append(False)
1117
1118
1119 rdc = array(rdc, float64)
1120 rdc_err = array(rdc_err, float64)
1121 rdc_weight = array(rdc_weight, float64)
1122 absolute = array(absolute, int32)
1123 T_flags = array(T_flags, int32)
1124 if not opt_uses_j_couplings():
1125 j_couplings = None
1126 pseudo_flags = array(pseudo_flags, int32)
1127
1128
1129 return rdc, rdc_err, rdc_weight, unit_vect, rdc_const, absolute, T_flags, j_couplings, pseudo_flags
1130
1131
1132 -def set_errors(align_id=None, spin_id1=None, spin_id2=None, sd=None):
1133 """Set the RDC errors if not already present.
1134
1135 @keyword align_id: The optional alignment tensor ID string.
1136 @type align_id: str
1137 @keyword spin_id1: The optional spin ID string of the first spin.
1138 @type spin_id1: None or str
1139 @keyword spin_id2: The optional spin ID string of the second spin.
1140 @type spin_id2: None or str
1141 @keyword sd: The RDC standard deviation in Hz.
1142 @type sd: float or int.
1143 """
1144
1145
1146 check_pipe_setup(sequence=True, rdc_id=align_id, rdc=True)
1147
1148
1149 if align_id:
1150 align_ids = [align_id]
1151 else:
1152 align_ids = cdp.rdc_ids
1153
1154
1155 for interatom in interatomic_loop(selection1=spin_id1, selection2=spin_id2):
1156
1157 if not hasattr(interatom, 'rdc_err'):
1158 interatom.rdc_err = {}
1159
1160
1161 for id in align_ids:
1162 interatom.rdc_err[id] = sd
1163
1164
1166 """Make sure that the interatom system is properly set up for pseudo-atoms and RDCs.
1167
1168 Interatomic data containers between the non-pseudo-atom and the pseudo-atom members will be deselected.
1169 """
1170
1171
1172 for interatom in interatomic_loop():
1173
1174 spin1 = return_spin(interatom.spin_id1)
1175 spin2 = return_spin(interatom.spin_id2)
1176
1177
1178 flag1 = is_pseudoatom(spin1)
1179 flag2 = is_pseudoatom(spin2)
1180
1181
1182 if not (flag1 or flag2):
1183 continue
1184
1185
1186 if flag1 and flag2:
1187 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)))
1188 interatom.select = False
1189
1190
1191 pseudospin = spin1
1192 base_spin_id = interatom.spin_id2
1193 pseudospin_id = interatom.spin_id1
1194 if flag2:
1195 pseudospin = spin2
1196 base_spin_id = interatom.spin_id1
1197 pseudospin_id = interatom.spin_id2
1198
1199
1200 for spin, spin_id in pseudoatom_loop(pseudospin, return_id=True):
1201
1202 pseudo_interatom = return_interatom(spin_id1=spin_id, spin_id2=base_spin_id)
1203
1204
1205 if pseudo_interatom.select:
1206 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)))
1207 pseudo_interatom.select = False
1208
1209
1210 -def weight(align_id=None, spin_id=None, weight=1.0):
1211 """Set optimisation weights on the RDC data.
1212
1213 @keyword align_id: The alignment tensor ID string.
1214 @type align_id: str
1215 @keyword spin_id: The spin ID string.
1216 @type spin_id: None or str
1217 @keyword weight: The optimisation weight. The higher the value, the more importance the RDC will have.
1218 @type weight: float or int.
1219 """
1220
1221
1222 check_pipe_setup(sequence=True, rdc_id=align_id, rdc=True)
1223
1224
1225 for interatom in interatomic_loop():
1226
1227 if not hasattr(interatom, 'rdc_weight'):
1228 interatom.rdc_weight = {}
1229
1230
1231 interatom.rdc_weight[align_id] = weight
1232
1233
1234 -def write(align_id=None, file=None, dir=None, bc=False, force=False):
1235 """Display the RDC data corresponding to the alignment ID.
1236
1237 @keyword align_id: The alignment tensor ID string.
1238 @type align_id: str
1239 @keyword file: The file name or object to write to.
1240 @type file: str or file object
1241 @keyword dir: The name of the directory to place the file into (defaults to the current directory).
1242 @type dir: str
1243 @keyword bc: The back-calculation flag which if True will cause the back-calculated rather than measured data to be written.
1244 @type bc: bool
1245 @keyword force: A flag which if True will cause any pre-existing file to be overwritten.
1246 @type force: bool
1247 """
1248
1249
1250 check_pipe_setup(sequence=True, rdc_id=align_id, rdc=True)
1251
1252
1253 file = open_write_file(file, dir, force)
1254
1255
1256 data = []
1257 for interatom in interatomic_loop():
1258
1259 if not interatom.select:
1260 continue
1261
1262
1263 if not bc and (not hasattr(interatom, 'rdc') or align_id not in interatom.rdc.keys()):
1264 continue
1265 elif bc and (not hasattr(interatom, 'rdc_bc') or align_id not in interatom.rdc_bc.keys()):
1266 continue
1267
1268
1269 data.append([])
1270 data[-1].append(repr(interatom.spin_id1))
1271 data[-1].append(repr(interatom.spin_id2))
1272
1273
1274 data_type = None
1275 if hasattr(interatom, 'rdc_data_types'):
1276 data_type = interatom.rdc_data_types[align_id]
1277
1278
1279 if bc:
1280 data[-1].append(repr(convert(interatom.rdc_bc[align_id], data_type, align_id)))
1281 else:
1282 data[-1].append(repr(convert(interatom.rdc[align_id], data_type, align_id)))
1283
1284
1285 if hasattr(interatom, 'rdc_err') and align_id in interatom.rdc_err.keys():
1286 data[-1].append(repr(convert(interatom.rdc_err[align_id], data_type, align_id)))
1287 else:
1288 data[-1].append(repr(None))
1289
1290
1291 write_data(out=file, headings=["Spin_ID1", "Spin_ID2", "RDCs", "RDC_error"], data=data)
1292