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 the molecule-residue-spin data structures in the relax data store.
24
25 The functionality of this module is diverse:
26 - Documentation for the spin identification string.
27 - Functions for parsing or generating spin identification strings.
28 - The mol-res-spin selection object (derived from the Selection class).
29 - Generator functions for looping over molecules, residues, or spins.
30 - Functions for returning MoleculeContainer, ResidueContainer, and SpinContainer objects or
31 information about these.
32 - Functions for copying, creating, deleting, displaying, naming, and numbering
33 MoleculeContainer, ResidueContainer, and SpinContainer objects in the relax data store.
34 - Functions for counting spins or testing their existence.
35 """
36
37
38 from numpy import array, float64
39 from re import split
40 import sys
41 from textwrap import fill
42 from warnings import warn
43
44
45 from check_types import is_unicode
46 from data.mol_res_spin import MoleculeContainer, ResidueContainer, SpinContainer
47 from generic_fns import exp_info, pipes, relax_re
48 from relax_errors import RelaxError, RelaxNoSpinError, RelaxMultiMolIDError, RelaxMultiResIDError, RelaxMultiSpinIDError, RelaxResSelectDisallowError, RelaxSpinSelectDisallowError
49 from relax_warnings import RelaxWarning
50 from status import Status; status = Status()
51 from user_functions.objects import Desc_container
52
53
54 ALLOWED_MOL_TYPES = ['protein',
55 'DNA',
56 'RNA',
57 'organic molecule',
58 'inorganic molecule'
59 ]
60 """The list of allowable molecule types."""
61
62 id_string_doc = Desc_container("Spin ID string documentation")
63 id_string_doc.add_paragraph("The identification string is composed of three components: the molecule ID token beginning with the '#' character, the residue ID token beginning with the ':' character, and the atom or spin system ID token beginning with the '@' character. Each token can be composed of multiple elements - one per spin - separated by the ',' character and each individual element can either be a number (which must be an integer, in string format), a name, or a range of numbers separated by the '-' character. Negative numbers are supported. The full ID string specification is '#<mol_name> :<res_id>[, <res_id>[, <res_id>, ...]] @<atom_id>[, <atom_id>[, <atom_id>, ...]]', where the token elements are '<mol_name>', the name of the molecule, '<res_id>', the residue identifier which can be a number, name, or range of numbers, '<atom_id>', the atom or spin system identifier which can be a number, name, or range of numbers.")
64 id_string_doc.add_paragraph("If one of the tokens is left out then all elements will be assumed to match. For example if the string does not contain the '#' character then all molecules will match the string. If only the molecule ID component is specified, then all spins of the molecule will match.")
65 id_string_doc.add_paragraph("Regular expression can be used to select spins. For example the string '@H*' will select the protons 'H', 'H2', 'H98'.")
66
67
68
70 """An object containing mol-res-spin selections.
71
72 A Selection object represents either a set of selected molecules, residues and spins, or the
73 union or intersection of two other Selection objects.
74 """
75
77 """Initialise a Selection object.
78
79 @param select_string: A mol-res-spin selection string.
80 @type select_string: string
81 """
82
83
84 if is_unicode(select_string):
85 select_string = str(select_string)
86
87 self._union = None
88 self._intersect = None
89
90 self.molecules = []
91 self.residues = []
92 self.spins = []
93
94 if not select_string:
95 return
96
97
98 and_index = select_string.rfind('&')
99 or_index = select_string.rfind('|')
100
101 if and_index > or_index:
102 sel0 = Selection(select_string[:and_index].strip())
103 sel1 = Selection(select_string[and_index+1:].strip())
104 self.intersection(sel0, sel1)
105
106 elif or_index > and_index:
107 sel0 = Selection(select_string[:or_index].strip())
108 sel1 = Selection(select_string[or_index+1:].strip())
109 self.union(sel0, sel1)
110
111
112 else:
113 mol_token, res_token, spin_token = tokenise(select_string)
114 self.molecules = parse_token(mol_token)
115 self.residues = parse_token(res_token)
116 self.spins = parse_token(spin_token)
117
118
120 """Replacement function for determining if an object matches the selection.
121
122 @param obj: The data object. This can be a MoleculeContainer, ResidueContainer, or
123 SpinContainer instance or a type of these instances. If a tuple, only one
124 type of object can be in the tuple.
125 @type obj: instance or type of instances.
126 @return: The answer of whether the object matches the selection.
127 @rtype: bool
128 """
129
130
131 if self._union:
132 return (obj in self._union[0]) or (obj in self._union[1])
133
134
135 elif self._intersect:
136 return (obj in self._intersect[0]) and (obj in self._intersect[1])
137
138
139 if isinstance(obj, str):
140 return self.__contains_spin_id(obj)
141
142
143 else:
144 return self.__contains_mol_res_spin_containers(obj)
145
146
148 """Are the MoleculeContainer, ResidueContainer, and/or SpinContainer in the selection.
149
150 @param obj: The data object. This can be a MoleculeContainer, ResidueContainer, or
151 SpinContainer instance or a type of these instances. If a tuple, only one
152 type of object can be in the tuple.
153 @type obj: instance or type of instances.
154 @return: The answer of whether the objects are found within the selection object.
155 @rtype: bool
156 """
157
158
159 mol = None
160 res = None
161 spin = None
162
163
164 if not isinstance(obj, tuple):
165 obj = (obj,)
166
167
168 if len(obj) > 3:
169 return False
170
171
172 for i in range(len(obj)):
173
174 if isinstance(obj[i], MoleculeContainer):
175
176 if mol != None:
177 raise RelaxError("Comparing two molecular containers simultaneously with the selection object is not supported.")
178
179
180 mol = obj[i]
181
182
183 elif isinstance(obj[i], ResidueContainer):
184
185 if res != None:
186 raise RelaxError("Comparing two residue containers simultaneously with the selection object is not supported.")
187
188
189 res = obj[i]
190
191
192 elif isinstance(obj[i], SpinContainer):
193
194 if spin != None:
195 raise RelaxError("Comparing two spin containers simultaneously with the selection object is not supported.")
196
197
198 spin = obj[i]
199
200
201 else:
202 return False
203
204
205 select_mol = False
206 select_res = False
207 select_spin = False
208
209
210 if mol:
211
212 if not self.molecules:
213 select_mol = True
214
215
216 elif relax_re.search(self.molecules, mol.name):
217 select_mol = True
218 else:
219
220 select_mol = True
221
222
223 if not select_mol:
224 return False
225
226
227 if res:
228
229 if not self.residues:
230 select_res = True
231
232
233 elif res.num in self.residues or relax_re.search(self.residues, res.name):
234 select_res = True
235 else:
236
237 select_res = True
238
239
240 if not select_res:
241 return False
242
243
244 if spin:
245
246 if not self.spins:
247 select_spin = True
248
249
250 elif spin.num in self.spins or relax_re.search(self.spins, spin.name):
251 select_spin = True
252 else:
253
254 select_spin = True
255
256
257 return select_mol and select_res and select_spin
258
259
261 """Is the molecule, residue, and/or spin of the spin_id string located in the selection.
262
263 Only the simple selections allowed by the tokenise function are currently supported.
264
265
266 @param spin_id: The spin identification string.
267 @type spin_id: str
268 @return: The answer of whether the molecule, residue, and/or spin corresponding to
269 the spin_id string found within the selection object.
270 @rtype: bool
271 """
272
273
274 try:
275 mol_token, res_token, spin_token = tokenise(spin_id)
276 molecules = parse_token(mol_token)
277 residues = parse_token(res_token)
278 spins = parse_token(spin_token)
279 except RelaxError:
280 warn(RelaxWarning("The spin identification string " + repr(spin_id) + " is too complex for the selection object."))
281
282
284 """Determine if the molecule name, in string form, is contained in this selection object.
285
286 @keyword mol: The name of the molecule.
287 @type mol: str or None
288 @return: The answer of whether the molecule is contained withing the selection
289 object.
290 @rtype: bool
291 """
292
293
294 if self._union:
295 return self._union[0].contains_mol(mol) or self._union[1].contains_mol(mol)
296
297
298 elif self._intersect:
299 return self._intersect[0].contains_mol(mol) and self._intersect[1].contains_mol(mol)
300
301
302 if relax_re.search(self.molecules, mol):
303 return True
304
305
306 if not self.molecules:
307 return True
308
309
310 return False
311
312
313 - def contains_res(self, res_num=None, res_name=None, mol=None):
314 """Determine if the residue name, in string form, is contained in this selection object.
315
316 @keyword res_num: The residue number.
317 @type res_num: int or None
318 @keyword res_name: The residue name.
319 @type res_name: str or None
320 @keyword mol: The molecule name.
321 @type mol: str or None
322 @return: The answer of whether the molecule is contained withing the selection
323 object.
324 @rtype: bool
325 """
326
327
328 if self._union:
329 return self._union[0].contains_res(res_num, res_name, mol) or self._union[1].contains_res(res_num, res_name, mol)
330
331
332 elif self._intersect:
333 return self._intersect[0].contains_res(res_num, res_name, mol) and self._intersect[1].contains_res(res_num, res_name, mol)
334
335
336 select_mol = self.contains_mol(mol)
337
338
339 select_res = False
340
341
342 if res_num in self.residues or relax_re.search(self.residues, res_name):
343 select_res = True
344
345
346 if not self.residues:
347 select_res = True
348
349
350 return select_res and select_mol
351
352
353 - def contains_spin(self, spin_num=None, spin_name=None, res_num=None, res_name=None, mol=None):
354 """Determine if the spin is contained in this selection object.
355
356 @keyword spin_num: The spin number.
357 @type spin_num: int or None
358 @keyword spin_name: The spin name.
359 @type spin_name: str or None
360 @keyword res_num: The residue number.
361 @type res_num: int or None
362 @keyword res_name: The residue name.
363 @type res_name: str or None
364 @keyword mol: The molecule name.
365 @type mol: str or None
366 @return: The answer of whether the spin is contained withing the selection
367 object.
368 @rtype: bool
369 """
370
371
372 if self._union:
373 return self._union[0].contains_spin(spin_num, spin_name, res_num, res_name, mol) or self._union[1].contains_spin(spin_num, spin_name, res_num, res_name, mol)
374
375
376 elif self._intersect:
377 return self._intersect[0].contains_spin(spin_num, spin_name, res_num, res_name, mol) and self._intersect[1].contains_spin(spin_num, spin_name, res_num, res_name, mol)
378
379
380 select_mol = self.contains_mol(mol)
381
382
383 select_res = self.contains_res(res_num, res_name, mol)
384
385
386 select_spin = False
387
388
389 if spin_num in self.spins or relax_re.search(self.spins, spin_name):
390 select_spin = True
391
392
393 if not self.spins:
394 select_spin = True
395
396
397 return select_spin and select_res and select_mol
398
399
401 """Determine if the selection object contains molecules.
402
403 @return: The answer of whether the selection contains molecules.
404 @rtype: bool
405 """
406
407
408 if self._union:
409 return self._union[0].has_molecules() or self._union[1].has_molecules()
410
411
412 elif self._intersect:
413 return self._intersect[0].has_molecules() and self._intersect[1].has_molecules()
414
415
416 if self.molecules:
417 return True
418
419
421 """Determine if the selection object contains residues.
422
423 @return: The answer of whether the selection contains residues.
424 @rtype: bool
425 """
426
427
428 if self._union:
429 return self._union[0].has_residues() or self._union[1].has_residues()
430
431
432 elif self._intersect:
433 return self._intersect[0].has_residues() and self._intersect[1].has_residues()
434
435
436 if self.residues:
437 return True
438
439
441 """Determine if the selection object contains spins.
442
443 @return: The answer of whether the selection contains spins.
444 @rtype: bool
445 """
446
447
448 if self._union:
449 return self._union[0].has_spins() or self._union[1].has_spins()
450
451
452 elif self._intersect:
453 return self._intersect[0].has_spins() and self._intersect[1].has_spins()
454
455
456 if self.spins:
457 return True
458
459
461 """Make this Selection object the intersection of two other Selection objects.
462
463 @param select_obj0: First Selection object in intersection.
464 @type select_obj0: Selection instance.
465 @param select_obj1: First Selection object in intersection.
466 @type select_obj1: Selection instance.
467 """
468
469
470 if self._union or self._intersect or self.molecules or self.residues or self.spins:
471 raise RelaxError("Cannot define multiple Boolean relationships between Selection objects")
472
473
474 self._intersect = (select_obj0, select_obj1)
475
476
477 - def union(self, select_obj0, select_obj1):
478 """Make this Selection object the union of two other Selection objects.
479
480 @param select_obj0: First Selection object in intersection.
481 @type select_obj0: Selection instance.
482 @param select_obj1: First Selection object in intersection.
483 @type select_obj1: Selection instance.
484 """
485
486
487 if self._union or self._intersect or self.molecules or self.residues or self.spins:
488 raise RelaxError("Cannot define multiple Boolean relationships between Selection objects")
489
490
491 self._union = (select_obj0, select_obj1)
492
493
494
496 """Determine if any spins have been named.
497
498 @keyword spin_id: The spin ID string.
499 @type spin_id: None or str
500 @return: True if a spin has been named or False if no spins have been named.
501 @rtype: bool
502 """
503
504
505 for spin in spin_loop(spin_id):
506
507 if spin.name != None:
508 return True
509
510
511 return False
512
513
515 """Generate the molecule and residue spin containers from the entity saveframe records.
516
517 @param star: The NMR-STAR dictionary object.
518 @type star: NMR_STAR instance
519 """
520
521
522 for data in star.entity.loop():
523
524 mol_name = data['mol_name']
525 if mol_name:
526
527 mol_name = mol_name.replace('(', '')
528 mol_name = mol_name.replace(')', '')
529
530
531 mol_name = mol_name.replace('[', '')
532 mol_name = mol_name.replace(']', '')
533
534
535 mol_name = mol_name.replace(',', ' ')
536
537
538 mol_type = data['mol_type']
539 polymer_type = data['polymer_type']
540
541
542 if mol_type == 'polymer':
543 map = {
544 'DNA/RNA hybrid': 'DNA',
545 'polydeoxyribonucleotide': 'DNA',
546 'polypeptide(D)': 'protein',
547 'polypeptide(L)': 'protein',
548 'polyribonucleotide': 'RNA',
549 'polysaccharide(D)': 'organic molecule',
550 'polysaccharide(L)': 'organic molecule'
551 }
552 mol_type = map[polymer_type]
553
554
555 create_molecule(mol_name=mol_name, mol_type=mol_type)
556
557
558 exp_info.thiol_state(data['thiol_state'])
559
560
561 for i in range(len(data['res_nums'])):
562 create_residue(data['res_nums'][i], data['res_names'][i], mol_name=mol_name)
563
564
566 """Generate the entity saveframe records for the NMR-STAR dictionary object.
567
568 @param star: The NMR-STAR dictionary object.
569 @type star: NMR_STAR instance
570 @keyword version: The BMRB NMR-STAR dictionary format to output to.
571 @type version: str
572 """
573
574
575 for mol in molecule_loop():
576
577 if not mol.name:
578 raise RelaxError("All molecules must be named.")
579
580
581 if not hasattr(mol, 'type') or not mol.type:
582 raise RelaxError("The molecule type for the '%s' molecule must be specified, please use the appropriate molecule user function to set this." % mol.name)
583
584
585 if not hasattr(cdp, 'exp_info') or not hasattr(cdp.exp_info, 'thiol_state'):
586 raise RelaxError("The thiol state of the molecule '%s' must be specified, please use the appropriate BMRB user function to set this." % mol.name)
587
588
589 res_names = get_residue_names("#" + mol.name)
590 res_nums = get_residue_nums("#" + mol.name)
591
592
593 polymer_seq_code = one_letter_code(res_names)
594
595
596 if mol.type in ['organic molecule', 'other']:
597 mol_type = 'non-polymer'
598 else:
599 mol_type = 'polymer'
600
601
602 polymer_type = mol.type
603 if polymer_type == 'protein':
604 polymer_type = 'polypeptide(L)'
605 if polymer_type == 'DNA':
606 polymer_type = 'polydeoxyribonucleotide'
607 if polymer_type == 'RNA':
608 polymer_type = 'polyribonucleotide'
609 if polymer_type == 'inorganic molecule':
610 polymer_type = 'other'
611
612
613 star.entity.add(mol_name=mol.name, mol_type=mol_type, polymer_type=polymer_type, polymer_seq_code=polymer_seq_code, thiol_state=cdp.exp_info.thiol_state, res_nums=res_nums, res_names=res_names)
614
615
616 -def copy_molecule(pipe_from=None, mol_from=None, pipe_to=None, mol_to=None):
617 """Copy the contents of a molecule container to a new molecule.
618
619 For copying to be successful, the mol_from identification string must match an existent molecule.
620
621 @param pipe_from: The data pipe to copy the molecule data from. This defaults to the current
622 data pipe.
623 @type pipe_from: str
624 @param mol_from: The molecule identification string for the structure to copy the data from.
625 @type mol_from: str
626 @param pipe_to: The data pipe to copy the molecule data to. This defaults to the current
627 data pipe.
628 @type pipe_to: str
629 @param mol_to: The molecule identification string for the structure to copy the data to.
630 @type mol_to: str
631 """
632
633
634 status.spin_lock.acquire(sys._getframe().f_code.co_name)
635 try:
636
637 if pipe_from == None:
638 pipe_from = pipes.cdp_name()
639 if pipe_to == None:
640 pipe_to = pipes.cdp_name()
641
642
643 pipes.test(pipe_to)
644
645
646 mol_from_token, res_from_token, spin_from_token = tokenise(mol_from)
647 mol_to_token, res_to_token, spin_to_token = tokenise(mol_to)
648
649
650 if spin_from_token != None or spin_to_token != None:
651 raise RelaxSpinSelectDisallowError
652
653
654 if res_from_token != None or res_to_token != None:
655 raise RelaxResSelectDisallowError
656
657
658 mol_name_to = return_single_molecule_info(mol_to_token)
659
660
661 mol_to_cont = return_molecule(mol_to, pipe_to)
662 if mol_to_cont and not mol_to_cont.is_empty():
663 raise RelaxError("The molecule " + repr(mol_to) + " already exists in the " + repr(pipe_to) + " data pipe.")
664
665
666 mol_from_cont = return_molecule(mol_from, pipe_from)
667
668
669 if mol_from_cont == None:
670 raise RelaxError("The molecule " + repr(mol_from) + " does not exist in the " + repr(pipe_from) + " data pipe.")
671
672
673 pipe = pipes.get_pipe(pipe_to)
674
675
676 if pipe.mol[0].name == None and len(pipe.mol) == 1:
677 pipe.mol[0] = mol_from_cont.__clone__()
678 else:
679 pipe.mol.append(mol_from_cont.__clone__())
680
681
682 if mol_name_to != None:
683 pipe.mol[-1].name = mol_name_to
684
685
686 metadata_update(pipe=pipe_to)
687
688
689 finally:
690 status.spin_lock.release(sys._getframe().f_code.co_name)
691
692
693 -def copy_residue(pipe_from=None, res_from=None, pipe_to=None, res_to=None):
694 """Copy the contents of the residue structure from one residue to a new residue.
695
696 For copying to be successful, the res_from identification string must match an existent residue.
697 The new residue number must be unique.
698
699 @param pipe_from: The data pipe to copy the residue from. This defaults to the current data
700 pipe.
701 @type pipe_from: str
702 @param res_from: The residue identification string for the structure to copy the data from.
703 @type res_from: str
704 @param pipe_to: The data pipe to copy the residue to. This defaults to the current data
705 pipe.
706 @type pipe_to: str
707 @param res_to: The residue identification string for the structure to copy the data to.
708 @type res_to: str
709 """
710
711
712 status.spin_lock.acquire(sys._getframe().f_code.co_name)
713 try:
714
715 if pipe_from == None:
716 pipe_from = pipes.cdp_name()
717 if pipe_to == None:
718 pipe_to = pipes.cdp_name()
719
720
721 pipes.test(pipe_to)
722
723
724 pipe = pipes.get_pipe(pipe_to)
725
726
727 mol_from_token, res_from_token, spin_from_token = tokenise(res_from)
728 mol_to_token, res_to_token, spin_to_token = tokenise(res_to)
729
730
731 if spin_from_token != None or spin_to_token != None:
732 raise RelaxSpinSelectDisallowError
733
734
735 res_num_to, res_name_to = return_single_residue_info(res_to_token)
736
737
738 res_to_cont = return_residue(res_to, pipe_to)
739 if res_to_cont and not res_to_cont.is_empty():
740 raise RelaxError("The residue " + repr(res_to) + " already exists in the " + repr(pipe_to) + " data pipe.")
741
742
743 res_from_cont = return_residue(res_from, pipe_from)
744
745
746 if res_from_cont == None:
747 raise RelaxError("The residue " + repr(res_from) + " does not exist in the " + repr(pipe_from) + " data pipe.")
748
749
750 mol_to_container = return_molecule(res_to, pipe_to)
751 if mol_to_container == None:
752 mol_to_container = pipe.mol[0]
753
754
755 if mol_to_container.res[0].num == None and mol_to_container.res[0].name == None and len(mol_to_container.res) == 1:
756 mol_to_container.res[0] = res_from_cont.__clone__()
757 else:
758 mol_to_container.res.append(res_from_cont.__clone__())
759
760
761 if res_num_to != None:
762 mol_to_container.res[-1].num = res_num_to
763 if res_name_to != None:
764 mol_to_container.res[-1].name = res_name_to
765
766
767 metadata_update(pipe=pipe_to)
768
769
770 finally:
771 status.spin_lock.release(sys._getframe().f_code.co_name)
772
773
774 -def copy_spin(pipe_from=None, spin_from=None, pipe_to=None, spin_to=None):
775 """Copy the contents of the spin structure from one spin to a new spin.
776
777 For copying to be successful, the spin_from identification string must match an existent spin.
778 The new spin number must be unique.
779
780 @param pipe_from: The data pipe to copy the spin from. This defaults to the current data
781 pipe.
782 @type pipe_from: str
783 @param spin_from: The spin identification string for the structure to copy the data from.
784 @type spin_from: str
785 @param pipe_to: The data pipe to copy the spin to. This defaults to the current data
786 pipe.
787 @type pipe_to: str
788 @param spin_to: The spin identification string for the structure to copy the data to.
789 @type spin_to: str
790 """
791
792
793 status.spin_lock.acquire(sys._getframe().f_code.co_name)
794 try:
795
796 if pipe_from == None:
797 pipe_from = pipes.cdp_name()
798 if pipe_to == None:
799 pipe_to = pipes.cdp_name()
800
801
802 pipes.test(pipe_to)
803
804
805 pipe = pipes.get_pipe(pipe_to)
806
807
808 mol_to_token, res_to_token, spin_to_token = tokenise(spin_to)
809
810
811 if spin_to_token:
812 spin_to_cont = return_spin(spin_to, pipe_to)
813 if spin_to_cont and not spin_to_cont.is_empty():
814 raise RelaxError("The spin " + repr(spin_to) + " already exists in the " + repr(pipe_from) + " data pipe.")
815
816
817 if not return_residue(spin_from, pipe_from):
818 raise RelaxError("The residue in " + repr(spin_from) + " does not exist in the " + repr(pipe_from) + " data pipe.")
819
820
821 spin_from_cont = return_spin(spin_from, pipe_from)
822 if spin_from_cont == None:
823 raise RelaxError("The spin " + repr(spin_from) + " does not exist in the " + repr(pipe_from) + " data pipe.")
824
825
826 res_to_cont = return_residue(spin_to, pipe_to)
827 if res_to_cont == None and spin_to:
828
829 raise RelaxError("The residue in " + repr(spin_to) + " does not exist in the " + repr(pipe_from) + " data pipe.")
830 if res_to_cont == None:
831 res_to_cont = pipe.mol[0].res[0]
832
833
834 if len(res_to_cont.spin) == 1 and res_to_cont.spin[0].is_empty():
835 res_to_cont.spin[0] = spin_from_cont.__clone__()
836 else:
837 res_to_cont.spin.append(spin_from_cont.__clone__())
838
839
840 spin_num_to, spin_name_to = return_single_spin_info(spin_to_token)
841
842
843 if spin_num_to != None:
844 res_to_cont.spin[-1].num = spin_num_to
845 if spin_name_to != None:
846 res_to_cont.spin[-1].name = spin_name_to
847
848
849 metadata_update(pipe=pipe_to)
850
851
852 finally:
853 status.spin_lock.release(sys._getframe().f_code.co_name)
854
855
857 """Count the number of molecules for which there is data.
858
859 @keyword selection: The selection string.
860 @type selection: str
861 @keyword pipe: The data pipe containing the spin. Defaults to the current data pipe.
862 @type pipe: str
863 @return: The number of non-empty molecules.
864 @rtype: int
865 """
866
867
868 if pipe == None:
869 pipe = pipes.cdp_name()
870
871
872 pipes.test(pipe)
873
874
875 if not exists_mol_res_spin_data(pipe=pipe):
876 return 0
877
878
879 mol_num = 0
880
881
882 for mol in molecule_loop(selection, pipe=pipe):
883 mol_num = mol_num + 1
884
885
886 return mol_num
887
888
890 """Count the number of residues for which there is data.
891
892 @keyword selection: The selection string.
893 @type selection: str
894 @keyword pipe: The data pipe containing the spin. Defaults to the current data pipe.
895 @type pipe: str
896 @return: The number of non-empty residues.
897 @rtype: int
898 """
899
900
901 if pipe == None:
902 pipe = pipes.cdp_name()
903
904
905 pipes.test(pipe)
906
907
908 if not exists_mol_res_spin_data(pipe=pipe):
909 return 0
910
911
912 res_num = 0
913
914
915 for res in residue_loop(selection, pipe=pipe):
916 res_num = res_num + 1
917
918
919 return res_num
920
921
922 -def count_spins(selection=None, pipe=None, skip_desel=True):
923 """Function for counting the number of spins for which there is data.
924
925 @keyword selection: The selection string.
926 @type selection: str
927 @keyword pipe: The data pipe containing the spin. Defaults to the current data pipe.
928 @type pipe: str
929 @keyword skip_desel: A flag which if true will cause deselected spins to be skipped in the
930 count.
931 @type skip_desel: bool
932 @return: The number of non-empty spins.
933 @rtype: int
934 """
935
936
937 if pipe == None:
938 pipe = pipes.cdp_name()
939
940
941 pipes.test(pipe)
942
943
944 if not exists_mol_res_spin_data(pipe=pipe):
945 return 0
946
947
948 spin_num = 0
949
950
951 for spin in spin_loop(selection, pipe=pipe):
952
953 if skip_desel and not spin.select:
954 continue
955
956 spin_num = spin_num + 1
957
958
959 return spin_num
960
961
963 """Add a molecule into the relax data store.
964
965 @keyword mol_name: The name of the molecule.
966 @type mol_name: str
967 @keyword pipe: The data pipe to add the molecule to. Defaults to the current data pipe.
968 @type pipe: str or None
969 @keyword mol_type: The type of molecule.
970 @type mol_type: str
971 @return: The newly created molecule.
972 @rtype: MoleculeContainer instance
973 """
974
975
976 if pipe == None:
977 pipe = pipes.cdp_name()
978
979
980 pipes.test(pipe)
981
982
983 dp = pipes.get_pipe(pipe)
984
985
986 status.spin_lock.acquire(sys._getframe().f_code.co_name)
987 try:
988
989 if mol_type and mol_type not in ALLOWED_MOL_TYPES:
990 raise RelaxError("The molecule type '%s' must be one of %s" % (mol_type, ALLOWED_MOL_TYPES))
991
992
993 for i in range(len(dp.mol)):
994 if dp.mol[i].name == mol_name:
995 raise RelaxError("The molecule '" + repr(mol_name) + "' already exists in the relax data store.")
996
997
998 dp.mol.add_item(mol_name=mol_name, mol_type=mol_type)
999
1000
1001 mol = dp.mol[-1]
1002
1003
1004 if len(dp.mol) == 2:
1005 metadata_prune(pipe=pipe)
1006 metadata_update(pipe=pipe)
1007 else:
1008 metadata_prune(mol_index=len(dp.mol)-1, pipe=pipe)
1009 metadata_update(mol_index=len(dp.mol)-1, pipe=pipe)
1010
1011
1012 finally:
1013 status.spin_lock.release(sys._getframe().f_code.co_name)
1014
1015
1016 return mol
1017
1018
1019 -def create_residue(res_num=None, res_name=None, mol_name=None, pipe=None):
1020 """Add a residue into the relax data store (and molecule if necessary).
1021
1022 @keyword res_num: The number of the new residue.
1023 @type res_num: int
1024 @keyword res_name: The name of the new residue.
1025 @type res_name: str
1026 @keyword mol_name: The name of the molecule to add the residue to.
1027 @type mol_name: str
1028 @keyword pipe: The data pipe to add the residue to. Defaults to the current data pipe.
1029 @type pipe: str or None
1030 @return: The newly created residue.
1031 @rtype: ResidueContainer instance
1032 """
1033
1034
1035 if pipe == None:
1036 pipe = pipes.cdp_name()
1037
1038
1039 pipes.test(pipe)
1040
1041
1042 status.spin_lock.acquire(sys._getframe().f_code.co_name)
1043 try:
1044
1045 mol_cont = return_molecule(generate_spin_id(mol_name=mol_name), pipe=pipe)
1046 if mol_cont == None:
1047 mol_cont = create_molecule(mol_name=mol_name, pipe=pipe)
1048
1049
1050 mol_cont.res.add_item(res_num=res_num, res_name=res_name)
1051
1052
1053 res = mol_cont.res[-1]
1054
1055
1056 if len(mol_cont.res) == 2:
1057 metadata_prune(mol_index=mol_cont._mol_index, pipe=pipe)
1058 metadata_update(mol_index=mol_cont._mol_index, pipe=pipe)
1059 else:
1060 metadata_prune(mol_index=mol_cont._mol_index, res_index=len(mol_cont.res)-1, pipe=pipe)
1061 metadata_update(mol_index=mol_cont._mol_index, res_index=len(mol_cont.res)-1, pipe=pipe)
1062
1063
1064 finally:
1065 status.spin_lock.release(sys._getframe().f_code.co_name)
1066
1067
1068 return res
1069
1070
1071 -def create_pseudo_spin(spin_name=None, spin_num=None, res_id=None, members=None, averaging=None, pipe=None):
1072 """Add a pseudo-atom spin container into the relax data store.
1073
1074 @param spin_name: The name of the new pseudo-spin.
1075 @type spin_name: str
1076 @param spin_num: The identification number of the new spin.
1077 @type spin_num: int
1078 @param res_id: The molecule and residue identification string.
1079 @type res_id: str
1080 @keyword pipe: The data pipe to add the spin to. Defaults to the current data pipe.
1081 @type pipe: str or None
1082 """
1083
1084
1085 if pipe == None:
1086 pipe = pipes.cdp_name()
1087
1088
1089 pipes.test()
1090
1091
1092 dp = pipes.get_pipe(pipe)
1093
1094
1095 status.spin_lock.acquire(sys._getframe().f_code.co_name)
1096 try:
1097
1098 mol_token, res_token, spin_token = tokenise(res_id)
1099
1100
1101 if spin_token != None:
1102 raise RelaxSpinSelectDisallowError
1103
1104
1105 if res_id:
1106 res_to_cont, mol_index, res_index = return_residue(res_id, pipe=pipe, indices=True)
1107 if res_to_cont == None:
1108 raise RelaxError("The residue in " + repr(res_id) + " does not exist in the current data pipe.")
1109 else:
1110 res_to_cont = dp.mol[0].res[0]
1111 mol_index = 0
1112 res_index = 0
1113
1114
1115 if averaging not in ['linear']:
1116 raise RelaxError("The '%s' averaging technique is unknown." % averaging)
1117
1118
1119 positions = []
1120 for atom in members:
1121
1122 spin = return_spin(atom, pipe=pipe)
1123
1124
1125 if spin == None:
1126 raise RelaxNoSpinError(atom)
1127
1128
1129 if not hasattr(spin, 'pos') or spin.pos == None:
1130 raise RelaxError("Positional information is not available for the atom '%s'." % atom)
1131
1132
1133 pos = spin.pos
1134
1135
1136 multi_model = True
1137 if type(pos[0]) in [float, float64]:
1138 multi_model = False
1139 pos = [pos]
1140
1141
1142 positions.append([])
1143 for i in range(len(pos)):
1144 positions[-1].append(pos[i].tolist())
1145
1146
1147 for atom in members:
1148
1149 spin = return_spin(atom, pipe=pipe)
1150
1151
1152 if res_id:
1153 spin.pseudo_name = res_id + '@' + spin_name
1154 else:
1155 spin.pseudo_name = '@' + spin_name
1156 spin.pseudo_num = spin_num
1157
1158
1159 res_to_cont.spin.add_item(spin_num=spin_num, spin_name=spin_name)
1160 spin = res_to_cont.spin[-1]
1161 spin_index = len(res_to_cont.spin) - 1
1162
1163
1164 spin.averaging = averaging
1165 spin.members = members
1166 if averaging == 'linear':
1167
1168 ave = linear_ave(positions)
1169
1170
1171 if multi_model:
1172 spin.pos = ave
1173 else:
1174 spin.pos = ave[0]
1175
1176
1177 metadata_prune(mol_index=mol_index, res_index=res_index, pipe=pipe)
1178 metadata_update(mol_index=mol_index, res_index=res_index, pipe=pipe)
1179
1180
1181 finally:
1182 status.spin_lock.release(sys._getframe().f_code.co_name)
1183
1184
1185 -def create_spin(spin_num=None, spin_name=None, res_num=None, res_name=None, mol_name=None, pipe=None):
1186 """Add a spin into the relax data store (and molecule and residue if necessary).
1187
1188 @keyword spin_num: The number of the new spin.
1189 @type spin_num: int
1190 @keyword spin_name: The name of the new spin.
1191 @type spin_name: str
1192 @keyword res_num: The number of the residue to add the spin to.
1193 @type res_num: int
1194 @keyword res_name: The name of the residue to add the spin to.
1195 @type res_name: str
1196 @keyword mol_name: The name of the molecule to add the spin to.
1197 @type mol_name: str
1198 @keyword pipe: The data pipe to add the spin to. Defaults to the current data pipe.
1199 @type pipe: str or None
1200 @return: The newly created spin.
1201 @rtype: SpinContainer instance
1202 """
1203
1204
1205 if pipe == None:
1206 pipe = pipes.cdp_name()
1207
1208
1209 pipes.test()
1210
1211
1212 dp = pipes.get_pipe(pipe)
1213
1214
1215 status.spin_lock.acquire(sys._getframe().f_code.co_name)
1216 try:
1217
1218 mol_index = index_molecule(mol_name)
1219 if mol_index == None:
1220 create_molecule(mol_name=mol_name, pipe=pipe)
1221 mol_index = len(dp.mol) - 1
1222
1223
1224 res_index = index_residue(res_num=res_num, res_name=res_name, mol_index=mol_index)
1225 if res_index == None:
1226 create_residue(mol_name=mol_name, res_num=res_num, res_name=res_name, pipe=pipe)
1227 res_index = len(dp.mol[mol_index].res) - 1
1228
1229
1230 res_cont = dp.mol[mol_index].res[res_index]
1231
1232
1233 if len(res_cont.spin) == 1 and res_cont.spin[0].is_empty():
1234 spin_cont = res_cont.spin[0]
1235 spin_cont.name = spin_name
1236 spin_cont.num = spin_num
1237
1238
1239 else:
1240 res_cont.spin.add_item(spin_num=spin_num, spin_name=spin_name)
1241 spin_cont = res_cont.spin[-1]
1242
1243
1244 spin_index = len(res_cont.spin) - 1
1245 spin_id = generate_spin_id(mol_name=mol_name, res_num=res_num, res_name=res_name, spin_num=spin_num, spin_name=spin_name)
1246
1247
1248 if len(res_cont.spin) == 2:
1249 metadata_prune(mol_index=mol_index, res_index=res_index, pipe=pipe)
1250 metadata_update(mol_index=mol_index, res_index=res_index, pipe=pipe)
1251 else:
1252 metadata_prune(mol_index=mol_index, res_index=res_index, spin_index=spin_index, pipe=pipe)
1253 metadata_update(mol_index=mol_index, res_index=res_index, spin_index=spin_index, pipe=pipe)
1254
1255
1256 finally:
1257 status.spin_lock.release(sys._getframe().f_code.co_name)
1258
1259
1260 return spin_cont
1261
1262
1264 """Convert the global index into the molecule, residue, and spin indices.
1265
1266 @param global_index: The global spin index, spanning the molecule and residue containers.
1267 @type global_index: int
1268 @param pipe: The data pipe containing the spin. Defaults to the current data
1269 pipe.
1270 @type pipe: str
1271 @return: The corresponding molecule, residue, and spin indices.
1272 @rtype: tuple of int
1273 """
1274
1275
1276 if pipe == None:
1277 pipe = pipes.cdp_name()
1278
1279
1280 pipes.test(pipe)
1281
1282
1283 spin_num = 0
1284 for mol_index, res_index, spin_index in spin_index_loop(pipe=pipe):
1285
1286 if spin_num == global_index:
1287 return mol_index, res_index, spin_index
1288
1289
1290 spin_num = spin_num + 1
1291
1292
1294 """Function for deleting molecules from the current data pipe.
1295
1296 @param mol_id: The molecule identifier string.
1297 @type mol_id: str
1298 """
1299
1300
1301 status.spin_lock.acquire(sys._getframe().f_code.co_name)
1302 try:
1303
1304 mol_token, res_token, spin_token = tokenise(mol_id)
1305
1306
1307 if spin_token != None:
1308 raise RelaxSpinSelectDisallowError
1309
1310
1311 if res_token != None:
1312 raise RelaxResSelectDisallowError
1313
1314
1315 molecules = parse_token(mol_token)
1316
1317
1318 indices = []
1319
1320
1321 for i in range(len(cdp.mol)):
1322
1323 if cdp.mol[i].name in molecules:
1324 indices.append(i)
1325
1326
1327 indices.reverse()
1328
1329
1330 for index in indices:
1331 metadata_prune(mol_index=index)
1332
1333
1334 for index in indices:
1335 cdp.mol.pop(index)
1336
1337
1338 if len(cdp.mol) == 0:
1339 cdp.mol.add_item()
1340
1341
1342 finally:
1343 status.spin_lock.release(sys._getframe().f_code.co_name)
1344
1345
1347 """Function for deleting residues from the current data pipe.
1348
1349 @param res_id: The molecule and residue identifier string.
1350 @type res_id: str
1351 """
1352
1353
1354 status.spin_lock.acquire(sys._getframe().f_code.co_name)
1355 try:
1356
1357 mol_token, res_token, spin_token = tokenise(res_id)
1358
1359
1360 if spin_token != None:
1361 raise RelaxSpinSelectDisallowError
1362
1363
1364 residues = parse_token(res_token)
1365
1366
1367 for mol in molecule_loop(res_id):
1368
1369 indices = []
1370
1371
1372 for i in range(len(mol.res)):
1373
1374 if mol.res[i].num in residues or mol.res[i].name in residues:
1375 indices.append(i)
1376
1377
1378 indices.reverse()
1379
1380
1381 for index in indices:
1382 metadata_prune(mol_index=mol._mol_index, res_index=index)
1383
1384
1385 for index in indices:
1386 mol.res.pop(index)
1387
1388
1389 if len(mol.res) == 0:
1390 mol.res.add_item()
1391
1392
1393 finally:
1394 status.spin_lock.release(sys._getframe().f_code.co_name)
1395
1396
1398 """Function for deleting spins from the current data pipe.
1399
1400 @param spin_id: The molecule, residue, and spin identifier string.
1401 @type spin_id: str
1402 """
1403
1404
1405 status.spin_lock.acquire(sys._getframe().f_code.co_name)
1406 try:
1407
1408
1409 mol_token, res_token, spin_token = tokenise(spin_id)
1410
1411
1412 spins = parse_token(spin_token)
1413
1414
1415 for res in residue_loop(spin_id):
1416
1417 indices = []
1418
1419
1420 for i in range(len(res.spin)):
1421
1422 if res.spin[i].num in spins or res.spin[i].name in spins:
1423 indices.append(i)
1424
1425
1426 indices.reverse()
1427
1428
1429 for index in indices:
1430 metadata_prune(mol_index=res._mol_index, res_index=res._res_index, spin_index=index)
1431
1432
1433 for index in indices:
1434 res.spin.pop(index)
1435
1436
1437 if len(res.spin) == 0:
1438 res.spin.add_item()
1439
1440
1441 finally:
1442 status.spin_lock.release(sys._getframe().f_code.co_name)
1443
1444
1446 """Function for displaying the information associated with the molecule.
1447
1448 @param mol_id: The molecule identifier string.
1449 @type mol_id: str
1450 """
1451
1452
1453 mol_token, res_token, spin_token = tokenise(mol_id)
1454
1455
1456 if res_token != None:
1457 raise RelaxResSelectDisallowError
1458 if spin_token != None:
1459 raise RelaxSpinSelectDisallowError
1460
1461
1462 if mol_token:
1463 mol_sel = '#' + mol_token
1464 else:
1465 mol_sel = None
1466
1467
1468 print("\n\n%-15s %-15s" % ("Molecule", "Number of residues"))
1469
1470
1471 for mol in molecule_loop(mol_sel):
1472
1473 print("%-15s %-15s" % (mol.name, repr(len(mol.res))))
1474
1475
1477 """Function for displaying the information associated with the residue.
1478
1479 @param res_id: The molecule and residue identifier string.
1480 @type res_id: str
1481 """
1482
1483
1484 mol_token, res_token, spin_token = tokenise(res_id)
1485
1486
1487 if spin_token != None:
1488 raise RelaxSpinSelectDisallowError
1489
1490
1491 print("\n\n%-15s %-15s %-15s %-15s" % ("Molecule", "Res number", "Res name", "Number of spins"))
1492
1493
1494 for res, mol_name in residue_loop(res_id, full_info=True):
1495 print("%-15s %-15s %-15s %-15s" % (mol_name, repr(res.num), res.name, repr(len(res.spin))))
1496
1497
1499 """Function for displaying the information associated with the spin.
1500
1501 @param spin_id: The molecule and residue identifier string.
1502 @type spin_id: str
1503 """
1504
1505
1506 print("\n\n%-15s %-15s %-15s %-15s %-15s" % ("Molecule", "Res number", "Res name", "Spin number", "Spin name"))
1507
1508
1509 for spin, mol_name, res_num, res_name in spin_loop(spin_id, full_info=True):
1510
1511 print("%-15s %-15s %-15s %-15s %-15s" % (mol_name, repr(res_num), res_name, repr(spin.num), spin.name))
1512
1513
1515 """Function for determining if any molecule-residue-spin data exists.
1516
1517 @keyword pipe: The data pipe in which the molecule-residue-spin data will be checked for.
1518 @type pipe: str
1519 @return: The answer to the question about the existence of data.
1520 @rtype: bool
1521 """
1522
1523
1524 if pipe == None:
1525 pipe = pipes.cdp_name()
1526
1527
1528 pipes.test(pipe)
1529
1530
1531 dp = pipes.get_pipe(pipe)
1532
1533
1534 if dp.mol.is_empty():
1535 return False
1536
1537
1538 return True
1539
1540
1541 -def find_index(selection=None, pipe=None, global_index=True):
1542 """Find and return the spin index or indices for the selection string.
1543
1544 @keyword selection: The spin selection identifier.
1545 @type selection: str
1546 @keyword pipe: The data pipe containing the spin. Defaults to the current data pipe.
1547 @type pipe: str
1548 @keyword global_index: A flag which if True will cause the global index to be returned. If
1549 False, then the molecule, residue, and spin indices will be returned.
1550 @type global_index: bool
1551 @return: The global spin index or the molecule, residue, and spin indices.
1552 @rtype: int or tuple of 3 int
1553 """
1554
1555
1556 if pipe == None:
1557 pipe = pipes.cdp_name()
1558
1559
1560 pipes.test(pipe)
1561
1562
1563 dp = pipes.get_pipe(pipe)
1564
1565
1566 select_obj = Selection(selection)
1567
1568
1569 global_i = -1
1570 mol_index = -1
1571
1572
1573 for mol in dp.mol:
1574
1575 mol_index = mol_index + 1
1576
1577
1578 res_index = -1
1579
1580
1581 for res in mol.res:
1582
1583 res_index = res_index + 1
1584
1585
1586 spin_index = -1
1587
1588
1589 for spin in res.spin:
1590
1591 spin_index = spin_index + 1
1592 global_i = global_i + 1
1593
1594
1595 if (mol, res, spin) in select_obj:
1596
1597 if global_index:
1598 return global_i
1599 else:
1600 return mol_index, res_index, spin_index
1601
1602
1604 """Determine the first residue number.
1605
1606 @return: The number of the first residue.
1607 @rtype: int
1608 """
1609
1610
1611 mol = return_molecule(selection)
1612
1613
1614 return mol.res[0].num
1615
1616
1617 -def generate_spin_id(mol_name=None, res_num=None, res_name=None, spin_num=None, spin_name=None):
1618 """Generate the spin selection string.
1619
1620 @param mol_name: The molecule name.
1621 @type mol_name: str or None
1622 @param res_num: The residue number.
1623 @type res_num: int or None
1624 @param res_name: The residue name.
1625 @type res_name: str or None
1626 @param spin_num: The spin number.
1627 @type spin_num: int or None
1628 @param spin_name: The spin name.
1629 @type spin_name: str or None
1630 @return: The spin identification string.
1631 @rtype: str
1632 """
1633
1634
1635 id = ""
1636
1637
1638 if mol_name != None:
1639 id = id + "#" + mol_name
1640
1641
1642 if res_num != None:
1643 id = id + ":" + str(res_num)
1644 elif res_name != None:
1645 id = id + ":" + res_name
1646
1647
1648 if spin_name != None:
1649 id = id + "@" + spin_name
1650 elif spin_num != None:
1651 id = id + "@" + str(spin_num)
1652
1653
1654 return id
1655
1656
1657 -def generate_spin_id_data_array(data=None, mol_name_col=None, res_num_col=None, res_name_col=None, spin_num_col=None, spin_name_col=None):
1658 """Generate the spin selection string from the given data array.
1659
1660 @param data: An array containing the molecule, residue, and/or spin data.
1661 @type data: list of str
1662 @param mol_name_col: The column containing the molecule name information.
1663 @type mol_name_col: int or None
1664 @param res_name_col: The column containing the residue name information.
1665 @type res_name_col: int or None
1666 @param res_num_col: The column containing the residue number information.
1667 @type res_num_col: int or None
1668 @param spin_name_col: The column containing the spin name information.
1669 @type spin_name_col: int or None
1670 @param spin_num_col: The column containing the spin number information.
1671 @type spin_num_col: int or None
1672 @return: The spin identification string.
1673 @rtype: str
1674 """
1675
1676
1677 id = ""
1678
1679
1680 if mol_name_col and data[mol_name_col-1] not in [None, 'None']:
1681 id = id + "#" + data[mol_name_col-1]
1682
1683
1684 if res_num_col and data[res_num_col-1] not in [None, 'None']:
1685 id = id + ":" + str(data[res_num_col-1])
1686 elif res_name_col and data[res_name_col-1] not in [None, 'None']:
1687 id = id + ":" + data[res_name_col-1]
1688
1689
1690 if spin_num_col and data[spin_num_col-1] not in [None, 'None']:
1691 id = id + "@" + str(data[spin_num_col-1])
1692 elif spin_name_col and data[spin_name_col-1] not in [None, 'None']:
1693 id = id + "@" + data[spin_name_col-1]
1694
1695
1696 return id
1697
1698
1700 """Return a list of the molecule ID strings.
1701
1702 @param selection: The molecule selection identifier.
1703 @type selection: str
1704 @return: The molecule ID strings.
1705 @rtype: list of str
1706 """
1707
1708
1709 mol_ids = []
1710 for mol, mol_id in molecule_loop(selection, return_id=True):
1711 mol_ids.append(mol_id)
1712
1713
1714 return mol_ids
1715
1716
1718 """Return a list of the molecule names.
1719
1720 @param selection: The molecule selection identifier.
1721 @type selection: str
1722 @return: The molecule names.
1723 @rtype: list of str
1724 """
1725
1726
1727 mol_names = []
1728 for mol in molecule_loop(selection):
1729 mol_names.append(mol.name)
1730
1731
1732 return mol_names
1733
1734
1736 """Return a list of the residue ID strings.
1737
1738 @param selection: The molecule and residue selection identifier.
1739 @type selection: str
1740 @return: The residue ID strings.
1741 @rtype: list of str
1742 """
1743
1744
1745 res_ids = []
1746 for res, res_id in residue_loop(selection, return_id=True):
1747 res_ids.append(res_id)
1748
1749
1750 return res_ids
1751
1752
1754 """Return a list of the residue names.
1755
1756 @param selection: The molecule and residue selection identifier.
1757 @type selection: str
1758 @return: The residue names.
1759 @rtype: list of str
1760 """
1761
1762
1763 res_names = []
1764 for res in residue_loop(selection):
1765 res_names.append(res.name)
1766
1767
1768 return res_names
1769
1770
1772 """Return a list of the residue numbers.
1773
1774 @param selection: The molecule and residue selection identifier.
1775 @type selection: str
1776 @return: The residue numbers.
1777 @rtype: list of str
1778 """
1779
1780
1781 res_nums = []
1782 for res in residue_loop(selection):
1783 res_nums.append(res.num)
1784
1785
1786 return res_nums
1787
1788
1790 """Return a list of the spin ID strings.
1791
1792 @param selection: The molecule and spin selection identifier.
1793 @type selection: str
1794 @return: The spin ID strings.
1795 @rtype: list of str
1796 """
1797
1798
1799 spin_ids = []
1800 for spin, spin_id in spin_loop(selection, return_id=True):
1801 spin_ids.append(spin_id)
1802
1803
1804 return spin_ids
1805
1806
1808 """Return the index of the molecule of the given name.
1809
1810 @keyword mol_name: The name of the molecule.
1811 @type mol_name: str or None
1812 @return: The index of the molecule, if it exists.
1813 @rtype: int or None
1814 """
1815
1816
1817 if mol_name == None and len(cdp.mol) == 1:
1818 return 0
1819
1820
1821 i = 0
1822 for mol in cdp.mol:
1823
1824 if mol.name == mol_name:
1825 return i
1826
1827
1828 i += 1
1829
1830
1831 return None
1832
1833
1835 """Return the index of the residue.
1836
1837 @keyword res_num: The number of the residue.
1838 @type res_num: int
1839 @keyword res_name: The name of the residue.
1840 @type res_name: str
1841 @keyword mol_index: The index of the molecule.
1842 @type mol_index: str
1843 @return: The index of the residue, if it exists.
1844 @rtype: int or None
1845 """
1846
1847
1848 if len(cdp.mol[mol_index].res) == 1 and res_num == cdp.mol[mol_index].res[0].num and res_name == cdp.mol[mol_index].res[0].name:
1849 return 0
1850
1851
1852 i = 0
1853 for res in cdp.mol[mol_index].res:
1854
1855 if res_num != None and res.num == res_num:
1856 return i
1857
1858
1859 if res_num == None and res_name != None and res.name == res_name:
1860 return i
1861
1862
1863 i += 1
1864
1865
1866 return None
1867
1868
1870 """Determine the last residue number.
1871
1872 @param selection: The molecule selection identifier.
1873 @type selection: str
1874 @return: The number of the last residue.
1875 @rtype: int
1876 """
1877
1878
1879 mol = return_molecule(selection)
1880
1881
1882 return mol.res[-1].num
1883
1884
1886 """Perform linear averaging of the atomic positions.
1887
1888 @param positions: The atomic positions. The first index is that of the positions to be averaged over. The second index is over the different models. The last index is over the x, y, and z coordinates.
1889 @type positions: list of lists of numpy float arrays
1890 @return: The averaged positions as a list of vectors.
1891 @rtype: list of numpy float arrays
1892 """
1893
1894
1895 ave = []
1896 for model_index in range(len(positions[0])):
1897
1898 ave.append(array([0.0, 0.0, 0.0]))
1899
1900
1901 for coord_index in range(3):
1902
1903 for atom_index in range(len(positions)):
1904 ave[model_index][coord_index] = ave[model_index][coord_index] + positions[atom_index][model_index][coord_index]
1905
1906
1907 ave[model_index][coord_index] = ave[model_index][coord_index] / len(positions)
1908
1909
1910 return ave
1911
1912
1979
1980
2062
2063
2065 """Generator function for looping over all the molecules of the given selection.
2066
2067 @param selection: The molecule selection identifier.
2068 @type selection: str
2069 @param pipe: The data pipe containing the molecule. Defaults to the current data pipe.
2070 @type pipe: str
2071 @keyword return_id: A flag which if True will cause the molecule identification string of the molecule spin to be returned in addition to the spin container.
2072 @type return_id: bool
2073 @return: The molecule specific data container.
2074 @rtype: instance of the MoleculeContainer class.
2075 """
2076
2077
2078 if pipe == None:
2079 pipe = pipes.cdp_name()
2080
2081
2082 pipes.test(pipe)
2083
2084
2085 dp = pipes.get_pipe(pipe)
2086
2087
2088 if not exists_mol_res_spin_data(pipe=pipe):
2089 return
2090
2091
2092 select_obj = Selection(selection)
2093
2094
2095 for mol in dp.mol:
2096
2097 if mol not in select_obj:
2098 continue
2099
2100
2101 if return_id:
2102 mol_id = generate_spin_id(mol.name)
2103
2104
2105 if return_id:
2106 yield mol, mol_id
2107 else:
2108 yield mol
2109
2110
2112 """Name the molecules.
2113
2114 @param mol_id: The molecule identification string.
2115 @type mol_id: str
2116 @param name: The new molecule name.
2117 @type name: str
2118 @keyword force: A flag which if True will cause the named molecule to be renamed.
2119 @type force: bool
2120 """
2121
2122
2123 status.spin_lock.acquire(sys._getframe().f_code.co_name)
2124 try:
2125
2126
2127 mol = return_molecule(mol_id)
2128
2129
2130 select_obj = Selection(mol_id)
2131 if select_obj.has_residues():
2132 raise RelaxResSelectDisallowError
2133 if select_obj.has_spins():
2134 raise RelaxSpinSelectDisallowError
2135
2136
2137 if mol:
2138 if mol.name and not force:
2139 warn(RelaxWarning("The molecule '%s' is already named. Set the force flag to rename." % mol_id))
2140 else:
2141 mol.name = name
2142
2143
2144 metadata_prune(mol_index=mol._mol_index)
2145 metadata_update(mol_index=mol._mol_index)
2146
2147
2148 finally:
2149 status.spin_lock.release(sys._getframe().f_code.co_name)
2150
2151
2153 """Name the residues.
2154
2155 @param res_id: The residue identification string.
2156 @type res_id: str
2157 @param name: The new residue name.
2158 @type name: str
2159 @keyword force: A flag which if True will cause the named residue to be renamed.
2160 @type force: bool
2161 """
2162
2163
2164 status.spin_lock.acquire(sys._getframe().f_code.co_name)
2165 try:
2166
2167 select_obj = Selection(res_id)
2168 if select_obj.has_spins():
2169 raise RelaxSpinSelectDisallowError
2170
2171
2172 for res, mol_name in residue_loop(res_id, full_info=True):
2173 if res.name and not force:
2174 warn(RelaxWarning("The residue '%s' is already named. Set the force flag to rename." % generate_spin_id(mol_name, res.num, res.name)))
2175 else:
2176 res.name = name
2177
2178
2179 metadata_prune(mol_index=res._mol_index, res_index=res._res_index)
2180 metadata_update(mol_index=res._mol_index, res_index=res._res_index)
2181
2182
2183 finally:
2184 status.spin_lock.release(sys._getframe().f_code.co_name)
2185
2186
2187 -def name_spin(spin_id=None, name=None, pipe=None, force=False):
2188 """Name the spins.
2189
2190 @keyword spin_id: The spin identification string.
2191 @type spin_id: str
2192 @keyword name: The new spin name.
2193 @type name: str
2194 @param pipe: The data pipe to operate on. Defaults to the current data pipe.
2195 @type pipe: str
2196 @keyword force: A flag which if True will cause the named spin to be renamed. If None, then the warning messages will not mention the need to change this flag to rename.
2197 @type force: bool or None
2198 """
2199
2200
2201 if pipe == None:
2202 pipe = pipes.cdp_name()
2203
2204
2205 pipes.test(pipe)
2206
2207
2208 status.spin_lock.acquire(sys._getframe().f_code.co_name)
2209 try:
2210
2211 for spin, id in spin_loop(spin_id, pipe=pipe, return_id=True):
2212 if spin.name and force != True:
2213 if force == False:
2214 warn(RelaxWarning("The spin '%s' is already named. Set the force flag to rename." % id))
2215 else:
2216 warn(RelaxWarning("The spin '%s' is already named." % id))
2217 else:
2218 spin.name = name
2219
2220
2221 metadata_prune(mol_index=spin._mol_index, res_index=spin._res_index, spin_index=spin._spin_index)
2222 metadata_update(mol_index=spin._mol_index, res_index=spin._res_index, spin_index=spin._spin_index)
2223
2224
2225 finally:
2226 status.spin_lock.release(sys._getframe().f_code.co_name)
2227
2228
2230 """Number the residues.
2231
2232 @param res_id: The residue identification string.
2233 @type res_id: str
2234 @param number: The new residue number.
2235 @type number: int
2236 @keyword force: A flag which if True will cause the numbered residue to be renumbered.
2237 @type force: bool
2238 """
2239
2240
2241 status.spin_lock.acquire(sys._getframe().f_code.co_name)
2242 try:
2243
2244 i = 0
2245 for res in residue_loop(res_id):
2246 i = i + 1
2247
2248
2249 if i > 1:
2250 raise RelaxError("The numbering of multiple residues is disallowed, each residue requires a unique number.")
2251
2252
2253 select_obj = Selection(res_id)
2254 if select_obj.has_spins():
2255 raise RelaxSpinSelectDisallowError
2256
2257
2258 for res, mol_name in residue_loop(res_id, full_info=True):
2259 if res.num and not force:
2260 warn(RelaxWarning("The residue '%s' is already numbered. Set the force flag to renumber." % generate_spin_id(mol_name, res.num, res.name)))
2261 else:
2262 res.num = number
2263
2264
2265 metadata_prune(mol_index=res._mol_index, res_index=res._res_index)
2266 metadata_update(mol_index=res._mol_index, res_index=res._res_index)
2267
2268
2269 finally:
2270 status.spin_lock.release(sys._getframe().f_code.co_name)
2271
2272
2273 -def number_spin(spin_id=None, number=None, force=False):
2274 """Number the spins.
2275
2276 @param spin_id: The spin identification string.
2277 @type spin_id: str
2278 @param number: The new spin number.
2279 @type number: int
2280 @keyword force: A flag which if True will cause the numbered spin to be renumbered.
2281 @type force: bool
2282 """
2283
2284
2285 status.spin_lock.acquire(sys._getframe().f_code.co_name)
2286 try:
2287
2288 i = 0
2289 for spin in spin_loop(spin_id):
2290 i = i + 1
2291
2292
2293 if number != None and i > 1:
2294 raise RelaxError("The numbering of multiple spins is disallowed, as each spin requires a unique number.")
2295
2296
2297 for spin, id in spin_loop(spin_id, return_id=True):
2298 if spin.num and not force:
2299 warn(RelaxWarning("The spin '%s' is already numbered. Set the force flag to renumber." % id))
2300 else:
2301 spin.num = number
2302
2303
2304 metadata_prune(mol_index=spin._mol_index, res_index=spin._res_index, spin_index=spin._spin_index)
2305 metadata_update(mol_index=spin._mol_index, res_index=spin._res_index, spin_index=spin._spin_index)
2306
2307
2308 finally:
2309 status.spin_lock.release(sys._getframe().f_code.co_name)
2310
2311
2313 """Convert the list of residue names into a string of one letter residue codes.
2314
2315 Standard amino acids are converted to the one letter code. Unknown residues are labelled as 'X'.
2316
2317
2318 @param res_names: A list of residue names.
2319 @type res_names: list or str
2320 @return: The one letter codes for the residues.
2321 @rtype: str
2322 """
2323
2324
2325 aa_table = [
2326 ['Alanine', 'ALA', 'A'],
2327 ['Arginine', 'ARG', 'R'],
2328 ['Asparagine', 'ASN', 'N'],
2329 ['Aspartic acid', 'ASP', 'D'],
2330 ['Cysteine', 'CYS', 'C'],
2331 ['Glutamic acid', 'GLU', 'E'],
2332 ['Glutamine', 'GLN', 'Q'],
2333 ['Glycine', 'GLY', 'G'],
2334 ['Histidine', 'HIS', 'H'],
2335 ['Isoleucine', 'ILE', 'I'],
2336 ['Leucine', 'LEU', 'L'],
2337 ['Lysine', 'LYS', 'K'],
2338 ['Methionine', 'MET', 'M'],
2339 ['Phenylalanine', 'PHE', 'F'],
2340 ['Proline', 'PRO', 'P'],
2341 ['Serine', 'SER', 'S'],
2342 ['Threonine', 'THR', 'T'],
2343 ['Tryptophan', 'TRP', 'W'],
2344 ['Tyrosine', 'TYR', 'Y'],
2345 ['Valine', 'VAL', 'V']
2346 ]
2347
2348
2349 seq = ''
2350 for res in res_names:
2351
2352 match = False
2353 for i in range(len(aa_table)):
2354 if res.upper() == aa_table[i][1]:
2355 seq = seq + aa_table[i][2]
2356 match = True
2357 break
2358
2359
2360 if not match:
2361 seq = seq + 'X'
2362
2363
2364 return seq
2365
2366
2368 """Parse the token string and return a list of identifying numbers and names.
2369
2370 Firstly the token is split by the ',' character into its individual elements and all whitespace
2371 stripped from the elements. Numbers are converted to integers, names are left as strings, and
2372 ranges are converted into the full list of integers.
2373
2374 @param token: The identification string, the elements of which are separated by commas.
2375 Each element can be either a single number, a range of numbers (two numbers
2376 separated by '-'), or a name.
2377 @type token: str
2378 @keyword verbosity: A flag which if True will cause a number of printouts to be activated.
2379 @type verbosity: bool
2380 @return: A list of identifying numbers and names.
2381 @rtype: list of int and str
2382 """
2383
2384
2385 if token == None:
2386 return []
2387
2388
2389 if not isinstance(token, list):
2390 tokens = [token]
2391 else:
2392 tokens = token
2393
2394
2395 id_list = []
2396 for token in tokens:
2397
2398 elements = split(',', token)
2399
2400
2401 for element in elements:
2402
2403 element = element.strip()
2404
2405
2406 indices= []
2407 for i in range(1, len(element)):
2408 if element[i] == '-':
2409 indices.append(i)
2410
2411
2412 valid_range = True
2413 if indices:
2414
2415 if len(indices) > 2:
2416 if verbosity:
2417 print("The range element " + repr(element) + " is invalid. Assuming the '-' character does not specify a range.")
2418 valid_range = False
2419
2420
2421 try:
2422 start = int(element[:indices[0]])
2423 end = int(element[indices[0]+1:])
2424 except ValueError:
2425 if verbosity:
2426 print("The range element " + repr(element) + " is invalid as either the start or end of the range are not integers. Assuming the '-' character does not specify a range.")
2427 valid_range = False
2428
2429
2430 if valid_range and start >= end:
2431 if verbosity:
2432 print("The starting number of the range element " + repr(element) + " needs to be less than the end number. Assuming the '-' character does not specify a range.")
2433 valid_range = False
2434
2435
2436 if valid_range:
2437 for i in range(start, end+1):
2438 id_list.append(i)
2439
2440
2441 else:
2442 id_list.append(element)
2443
2444
2445 else:
2446
2447 try:
2448 element = int(element)
2449 except ValueError:
2450 pass
2451
2452
2453 id_list.append(element)
2454
2455
2456 return id_list
2457
2458
2459 -def residue_loop(selection=None, pipe=None, full_info=False, return_id=False):
2460 """Generator function for looping over all the residues of the given selection.
2461
2462 @param selection: The residue selection identifier.
2463 @type selection: str
2464 @param pipe: The data pipe containing the residue. Defaults to the current data pipe.
2465 @type pipe: str
2466 @param full_info: A flag specifying if the amount of information to be returned. If false, only the data container is returned. If true, the molecule name, residue number, and residue name is additionally returned.
2467 @type full_info: boolean
2468 @keyword return_id: A flag which if True will cause the molecule identification string of the molecule spin to be returned in addition to the spin container.
2469 @type return_id: bool
2470 @return: The residue specific data container and, if full_info=True, the molecule name.
2471 @rtype: instance of the ResidueContainer class. If full_info=True, the type is the tuple (ResidueContainer, str).
2472 """
2473
2474
2475 if pipe == None:
2476 pipe = pipes.cdp_name()
2477
2478
2479 pipes.test(pipe)
2480
2481
2482 dp = pipes.get_pipe(pipe)
2483
2484
2485 if not exists_mol_res_spin_data(pipe=pipe):
2486 return
2487
2488
2489 select_obj = Selection(selection)
2490
2491
2492 for mol in dp.mol:
2493
2494 for res in mol.res:
2495
2496 if (mol, res) not in select_obj:
2497 continue
2498
2499
2500 if return_id:
2501 res_id = generate_spin_id(mol.name, res.num, res.name)
2502
2503
2504 if full_info and return_id:
2505 yield res, mol.name, res_id
2506 elif full_info:
2507 yield res, mol.name
2508 elif return_id:
2509 yield res, res_id
2510 else:
2511 yield res
2512
2513
2515 """Function for returning the molecule data container of the given selection.
2516
2517 @param selection: The molecule selection identifier.
2518 @type selection: str
2519 @param pipe: The data pipe containing the molecule. Defaults to the current data pipe.
2520 @type pipe: str
2521 @return: The molecule specific data container.
2522 @rtype: instance of the MoleculeContainer class.
2523 """
2524
2525
2526 if pipe == None:
2527 pipe = pipes.cdp_name()
2528
2529
2530 pipes.test(pipe)
2531
2532
2533 dp = pipes.get_pipe(pipe)
2534
2535
2536 select_obj = Selection(selection)
2537
2538
2539 mol_num = 0
2540 mol_container = None
2541 for mol in dp.mol:
2542
2543 if mol not in select_obj:
2544 continue
2545
2546
2547 if selection == None and mol.name != None:
2548 continue
2549
2550
2551 mol_container = mol
2552
2553
2554 mol_num = mol_num + 1
2555
2556
2557 if mol_num > 1:
2558 raise RelaxMultiMolIDError(selection)
2559
2560
2561 return mol_container
2562
2563
2565 """Function for returning the residue data container of the given selection.
2566
2567 @param selection: The residue selection identifier.
2568 @type selection: str
2569 @param pipe: The data pipe containing the residue. Defaults to the current data pipe.
2570 @type pipe: str
2571 @return: The residue specific data container, and the molecule and residue indices if asked.
2572 @rtype: instance of the ResidueContainer class.
2573 """
2574
2575
2576 if pipe == None:
2577 pipe = pipes.cdp_name()
2578
2579
2580 pipes.test(pipe)
2581
2582
2583 dp = pipes.get_pipe(pipe)
2584
2585
2586 select_obj = Selection(selection)
2587
2588
2589 res = None
2590 res_num = 0
2591 res_container = None
2592 for i in range(len(dp.mol)):
2593
2594 if dp.mol[i] not in select_obj:
2595 continue
2596
2597
2598 mol_index = i
2599
2600
2601 for j in range(len(dp.mol[i].res)):
2602
2603 if dp.mol[i].res[j] not in select_obj:
2604 continue
2605
2606
2607 res_container = dp.mol[i].res[j]
2608 res_index = j
2609
2610
2611 res_num = res_num + 1
2612
2613
2614 if res_num > 1:
2615 raise RelaxMultiResIDError(selection)
2616
2617
2618 if indices:
2619 return res_container, mol_index, res_index
2620 else:
2621 return res_container
2622
2623
2624 -def return_spin(spin_id=None, pipe=None, full_info=False, multi=False):
2625 """Return the spin data container corresponding to the given spin ID string.
2626
2627 @keyword spin_id: The unique spin ID string.
2628 @type spin_id: str
2629 @keyword pipe: The data pipe containing the spin. Defaults to the current data pipe.
2630 @type pipe: str
2631 @keyword full_info: A flag specifying if the amount of information to be returned. If false, only the data container is returned. If true, the molecule name, residue number, and residue name is additionally returned.
2632 @type full_info: bool
2633 @keyword multi: A flag which if True will allow multiple spins to be returned.
2634 @type multi: bool
2635 @return: The spin system specific data container and, if full_info=True, the molecule name, residue number, and residue name.
2636 @rtype: SpinContainer instance of list of instances or tuple of (str, int, str, SpinContainer instance or list of instances)
2637 """
2638
2639
2640 if pipe == None:
2641 pipe = pipes.cdp_name()
2642
2643
2644 dp = pipes.get_pipe(pipe)
2645
2646
2647 if spin_id not in dp.mol._spin_id_lookup:
2648 return None
2649
2650
2651 else:
2652 mol_index, res_index, spin_index = dp.mol._spin_id_lookup[spin_id]
2653
2654
2655 if full_info and multi:
2656 return [dp.mol[mol_index].name], [dp.mol[mol_index].res[res_index].num], [dp.mol[mol_index].res[res_index].name], [dp.mol[mol_index].res[res_index].spin[spin_index]]
2657 elif full_info:
2658 return dp.mol[mol_index].name, dp.mol[mol_index].res[res_index].num, dp.mol[mol_index].res[res_index].name, dp.mol[mol_index].res[res_index].spin[spin_index]
2659 elif multi:
2660 return [dp.mol[mol_index].res[res_index].spin[spin_index]]
2661 else:
2662 return dp.mol[mol_index].res[res_index].spin[spin_index]
2663
2664
2666 """Function for returning the spin data container of the given selection.
2667
2668 If more than one selection is given, then the boolean AND operation will be used to pull out the spin.
2669
2670 @keyword selection: The spin selection identifier.
2671 @type selection: str
2672 @keyword pipe: The data pipe containing the spin. Defaults to the current data pipe.
2673 @type pipe: str
2674 @keyword full_info: A flag specifying if the amount of information to be returned. If false, only the data container is returned. If true, the molecule name, residue number, and residue name is additionally returned.
2675 @type full_info: bool
2676 @keyword multi: A flag which if True will allow multiple spins to be returned.
2677 @type multi: bool
2678 @return: The spin system specific data container and, if full_info=True, the molecule name, residue number, and residue name.
2679 @rtype: SpinContainer instance of list of instances or tuple of (str, int, str, SpinContainer instance or list of instances)
2680 """
2681
2682
2683 if is_unicode(selection):
2684 selection = str(selection)
2685
2686
2687 if pipe == None:
2688 pipe = pipes.cdp_name()
2689
2690
2691 dp = pipes.get_pipe(pipe)
2692
2693
2694 select_obj = Selection(selection)
2695
2696
2697 spin_num = 0
2698 spins = []
2699 mol_names = []
2700 res_nums = []
2701 res_names = []
2702 spin_ids = []
2703 for mol in dp.mol:
2704
2705 if mol not in select_obj:
2706 continue
2707
2708
2709 for res in mol.res:
2710
2711 if res not in select_obj:
2712 continue
2713
2714
2715 for spin in res.spin:
2716
2717 if spin not in select_obj:
2718 continue
2719
2720
2721 mol_names.append(mol.name)
2722 res_nums.append(res.num)
2723 res_names.append(res.name)
2724 spins.append(spin)
2725
2726
2727 spin_num = spin_num + 1
2728
2729
2730 spin_ids.append(generate_spin_id(mol_name=mol.name, res_num=res.num, res_name=res.name, spin_num=spin.num, spin_name=spin.name))
2731
2732
2733 if not multi and spin_num > 1:
2734 raise RelaxMultiSpinIDError(selection, spin_ids)
2735
2736
2737 if full_info and multi:
2738 return mol_names, res_nums, res_names, spins
2739 elif full_info:
2740 return mol_names[0], res_nums[0], res_names[0], spins[0]
2741 elif multi:
2742 return spins
2743 elif len(spins):
2744 return spins[0]
2745 else:
2746 return None
2747
2748
2750 """Function for returning the spin data container corresponding to the global index.
2751
2752 @param global_index: The global spin index, spanning the molecule and residue containers.
2753 @type global_index: int
2754 @param pipe: The data pipe containing the spin. Defaults to the current data
2755 pipe.
2756 @type pipe: str
2757 @keyword return_spin_id: A flag which if True will cause both the spin container and spin
2758 identification string to be returned.
2759 @type return_spin_id: bool
2760 @return: The spin specific data container (additionally the spin
2761 identification string if return_spin_id is set).
2762 @rtype: instance of the SpinContainer class (or tuple of SpinContainer and
2763 str)
2764 """
2765
2766
2767 if pipe == None:
2768 pipe = pipes.cdp_name()
2769
2770
2771 pipes.test(pipe)
2772
2773
2774 spin_num = 0
2775 for spin, mol_name, res_num, res_name in spin_loop(full_info=True, pipe=pipe):
2776
2777 if spin_num == global_index:
2778
2779 if return_spin_id:
2780
2781 spin_id = generate_spin_id(mol_name, res_num, res_name, spin.num, spin.name)
2782
2783
2784 return spin, spin_id
2785
2786
2787 else:
2788 return spin
2789
2790
2791 spin_num = spin_num + 1
2792
2793
2795 """Return the molecule, residue and spin indices corresponding to the given spin ID string.
2796
2797 @keyword spin_id: The unique spin ID string.
2798 @type spin_id: str
2799 @param pipe: The data pipe containing the spin. Defaults to the current data pipe.
2800 @type pipe: str
2801 @return: The molecule, residue and spin indices.
2802 @rtype: list of int
2803 """
2804
2805
2806 if pipe == None:
2807 pipe = pipes.cdp_name()
2808
2809
2810 dp = pipes.get_pipe(pipe)
2811
2812
2813 if spin_id not in dp.mol._spin_id_lookup:
2814
2815 select_obj = Selection(spin_id)
2816
2817
2818 for i in range(len(dp.mol)):
2819
2820 if dp.mol[i] not in select_obj:
2821 continue
2822
2823
2824 mol_index = i
2825
2826
2827 for j in range(len(dp.mol[i].res)):
2828
2829 if dp.mol[i].res[j] not in select_obj:
2830 continue
2831
2832
2833 res_index = j
2834
2835
2836 for k in range(len(dp.mol[i].res[j].spin)):
2837
2838 if dp.mol[i].res[j].spin[k] not in select_obj:
2839 continue
2840
2841
2842 spin_index = k
2843
2844
2845 break
2846
2847
2848 else:
2849 mol_index, res_index, spin_index = dp.mol._spin_id_lookup[spin_id]
2850
2851
2852 return mol_index, res_index, spin_index
2853
2854
2856 """Return the single molecule name corresponding to the molecule token.
2857
2858 @param molecule_token: The molecule identification string.
2859 @type molecule_token: str
2860 @return: The molecule name.
2861 @rtype: str
2862 """
2863
2864
2865 molecule_info = parse_token(molecule_token)
2866
2867
2868 mol_name = None
2869 for info in molecule_info:
2870
2871 if mol_name == None:
2872 mol_name = info
2873 else:
2874 raise RelaxError("The molecule identifier " + repr(molecule_token) + " does not correspond to a single molecule.")
2875
2876
2877 if mol_name != None and not isinstance(mol_name, str):
2878 mol_name = str(mol_name)
2879
2880
2881 return mol_name
2882
2883
2885 """Return the single residue number and name corresponding to the residue token.
2886
2887 @param residue_token: The residue identification string.
2888 @type residue_token: str
2889 @return: A tuple containing the residue number and the residue name.
2890 @rtype: (int, str)
2891 """
2892
2893
2894 residue_info = parse_token(residue_token)
2895
2896
2897 res_num = None
2898 res_name = None
2899 for info in residue_info:
2900
2901 if isinstance(info, str):
2902 if res_name == None:
2903 res_name = info
2904 else:
2905 raise RelaxError("The residue identifier " + repr(residue_token) + " does not correspond to a single residue.")
2906
2907
2908 if isinstance(info, int):
2909 if res_num == None:
2910 res_num = info
2911 else:
2912 raise RelaxError("The residue identifier " + repr(residue_token) + " does not correspond to a single residue.")
2913
2914
2915 return res_num, res_name
2916
2917
2919 """Return the single spin number and name corresponding to the spin token.
2920
2921 @param spin_token: The spin identification string.
2922 @type spin_token: str
2923 @return: A tuple containing the spin number and the spin name.
2924 @rtype: (int, str)
2925 """
2926
2927
2928 spin_info = parse_token(spin_token)
2929
2930
2931 spin_num = None
2932 spin_name = None
2933 for info in spin_info:
2934
2935 if isinstance(info, str):
2936 if spin_name == None:
2937 spin_name = info
2938 else:
2939 raise RelaxError("The spin identifier " + repr(spin_token) + " does not correspond to a single spin.")
2940
2941
2942 if isinstance(info, int):
2943 if spin_num == None:
2944 spin_num = info
2945 else:
2946 raise RelaxError("The spin identifier " + repr(spin_token) + " does not correspond to a single spin.")
2947
2948
2949 return spin_num, spin_name
2950
2951
2953 """Test if the sequence data in both pipes are the same.
2954
2955 @param pipe1: The first data pipe.
2956 @type pipe1: str
2957 @param pipe2: The second data pipe.
2958 @type pipe2: str
2959 @return: True if the sequence data matches, False otherwise.
2960 @rtype: bool
2961 """
2962
2963
2964 pipes.test(pipe1)
2965 pipes.test(pipe2)
2966
2967
2968 pipe1 = pipes.get_pipe(pipe1)
2969 pipe2 = pipes.get_pipe(pipe2)
2970
2971
2972 if len(pipe1.mol) != len(pipe2.mol):
2973 return False
2974
2975
2976 for i in range(len(pipe1.mol)):
2977
2978 if len(pipe1.mol[i].res) != len(pipe2.mol[i].res):
2979 return False
2980
2981
2982 for j in range(len(pipe1.mol[i].res)):
2983
2984 if len(pipe1.mol[i].res[j].spin) != len(pipe2.mol[i].res[j].spin):
2985 return False
2986
2987
2988 for k in range(len(pipe1.mol[i].res[j].spin)):
2989
2990 if pipe1.mol[i].res[j].spin[k].num != pipe2.mol[i].res[j].spin[k].num:
2991 return False
2992
2993
2994 if pipe1.mol[i].res[j].spin[k].name != pipe2.mol[i].res[j].spin[k].name:
2995 return False
2996
2997
2998 return True
2999
3000
3002 """Set the element type of the spins.
3003
3004 @keyword spin_id: The spin identification string.
3005 @type spin_id: str
3006 @keyword element: The IUPAC element name.
3007 @type element: str
3008 @param pipe: The data pipe to operate on. Defaults to the current data pipe.
3009 @type pipe: str
3010 @keyword force: A flag which if True will cause the element to be changed.
3011 @type force: bool
3012 """
3013
3014
3015 valid_names = ['H',
3016 'C',
3017 'N',
3018 'O',
3019 'F',
3020 'Na',
3021 'P',
3022 'Cd'
3023 ]
3024
3025
3026 if element not in valid_names:
3027 raise RelaxError("The element name '%s' is not valid and should be one of the IUPAC names %s." % (element, valid_names))
3028
3029
3030 if pipe == None:
3031 pipe = pipes.cdp_name()
3032
3033
3034 pipes.test(pipe)
3035
3036
3037 for spin, id in spin_loop(spin_id, pipe=pipe, return_id=True):
3038 if hasattr(spin, 'element') and spin.element and not force:
3039 warn(RelaxWarning("The element type of the spin '%s' is already set. Set the force flag to True to rename." % id))
3040 else:
3041 spin.element = element
3042
3043
3045 """Set the nuclear isotope type of the spins.
3046
3047 @keyword spin_id: The spin identification string.
3048 @type spin_id: str
3049 @keyword isotope: The nuclear isotope type.
3050 @type isotope: str
3051 @param pipe: The data pipe to operate on. Defaults to the current data pipe.
3052 @type pipe: str
3053 @keyword force: A flag which if True will cause the isotope type to be changed. If None, then the warning messages will not mention the need to change this flag to rename.
3054 @type force: bool or None
3055 """
3056
3057
3058 supported_types = [
3059 '1H',
3060 '2H',
3061 '13C',
3062 '14N',
3063 '15N',
3064 '17O',
3065 '19F',
3066 '23Na',
3067 '31P',
3068 '113Cd'
3069 ]
3070
3071
3072 if isotope not in supported_types:
3073 raise RelaxError("The nuclear isotope type '%s' is currently not supported." % isotope)
3074
3075
3076 if pipe == None:
3077 pipe = pipes.cdp_name()
3078
3079
3080 pipes.test(pipe)
3081
3082
3083 for spin, id in spin_loop(spin_id, pipe=pipe, return_id=True):
3084 if hasattr(spin, 'isotope') and spin.isotope and force != True:
3085 if force == False:
3086 warn(RelaxWarning("The nuclear isotope type of the spin '%s' is already set. Change the force flag to True to reset." % id))
3087 else:
3088 warn(RelaxWarning("The nuclear isotope type of the spin '%s' is already set." % id))
3089 else:
3090 spin.isotope = isotope
3091
3092
3094 """Convert the single spin ID string into a list of the mol, res, and spin names and numbers.
3095
3096 @param id: The spin ID string.
3097 @type id: str
3098 @return: The molecule name, the residue number and name, and the spin number and name.
3099 @rtype: str, int, str, int, str
3100 """
3101
3102
3103 mol_token, res_token, spin_token = tokenise(id)
3104 mol_info = parse_token(mol_token)
3105 res_info = parse_token(res_token)
3106 spin_info = parse_token(spin_token)
3107
3108
3109 mol_name = None
3110 if len(mol_info) > 1:
3111 raise RelaxError("The single spin ID '%s' should only belong to one molecule, not %s." % (id, mol_info))
3112 if len(mol_info) == 1:
3113 mol_name = mol_info[0]
3114
3115
3116 res_names = []
3117 res_nums = []
3118 for i in range(len(res_info)):
3119 try:
3120 res_nums.append(int(res_info[i]))
3121 except ValueError:
3122 res_names.append(res_info[i])
3123
3124
3125 res_num = None
3126 if len(res_nums) > 1:
3127 raise RelaxError("The single spin ID '%s' should only belong to one residue number, not %s." % (id, res_info))
3128 elif len(res_nums) == 1:
3129 res_num = res_nums[0]
3130
3131
3132 res_name = None
3133 if len(res_names) > 1:
3134 raise RelaxError("The single spin ID '%s' should only belong to one residue name, not %s." % (id, res_info))
3135 elif len(res_names) == 1:
3136 res_name = res_names[0]
3137
3138
3139 spin_names = []
3140 spin_nums = []
3141 for i in range(len(spin_info)):
3142 try:
3143 spin_nums.append(int(spin_info[i]))
3144 except ValueError:
3145 spin_names.append(spin_info[i])
3146
3147
3148 spin_num = None
3149 if len(spin_nums) > 1:
3150 raise RelaxError("The single spin ID '%s' should only belong to one spin number, not %s." % (id, spin_info))
3151 elif len(spin_nums) == 1:
3152 spin_num = spin_nums[0]
3153
3154
3155 spin_name = None
3156 if len(spin_names) > 1:
3157 raise RelaxError("The single spin ID '%s' should only belong to one spin name, not %s." % (id, spin_info))
3158 elif len(spin_names) == 1:
3159 spin_name = spin_names[0]
3160
3161
3162 return mol_name, res_num, res_name, spin_num, spin_name
3163
3164
3165 -def spin_id_variants(dp=None, mol_index=None, res_index=None, spin_index=None):
3166 """Generate a list of spin ID variants for the given set of molecule, residue and spin indices.
3167
3168 @keyword dp: The data pipe to work on.
3169 @type dp: PipeContainer instance
3170 @keyword mol_index: The molecule index.
3171 @type mol_index: int
3172 @keyword res_index: The residue index.
3173 @type res_index: int
3174 @keyword spin_index: The spin index.
3175 @type spin_index: int
3176 @return: The list of all spin IDs matching the spin.
3177 @rtype: list of str
3178 """
3179
3180
3181 spin_ids = []
3182 mol = dp.mol[mol_index]
3183 res = dp.mol[mol_index].res[res_index]
3184 spin = dp.mol[mol_index].res[res_index].spin[spin_index]
3185 mol_count = len(dp.mol)
3186 res_count = len(mol.res)
3187 spin_count = len(res.spin)
3188
3189
3190 spin_ids.append(generate_spin_id(mol_name=mol.name, res_num=res.num, res_name=res.name, spin_num=spin.num, spin_name=spin.name))
3191
3192
3193 if spin_count == 1:
3194 spin_ids.append(generate_spin_id(mol_name=mol.name, res_num=res.num, res_name=res.name))
3195
3196
3197 if res_count == 1:
3198 spin_ids.append(generate_spin_id(mol_name=mol.name, spin_num=spin.num, spin_name=spin.name))
3199
3200
3201 if mol_count == 1:
3202 spin_ids.append(generate_spin_id(res_num=res.num, res_name=res.name, spin_num=spin.num, spin_name=spin.name))
3203
3204
3205 if spin_count == 1 and res_count == 1:
3206 spin_ids.append(generate_spin_id(mol_name=mol.name))
3207
3208
3209 if spin_count == 1 and mol_count == 1:
3210 spin_ids.append(generate_spin_id(res_num=res.num, res_name=res.name))
3211
3212
3213 if res_count == 1 and mol_count == 1:
3214 spin_ids.append(generate_spin_id(spin_num=spin.num, spin_name=spin.name))
3215
3216
3217 return spin_ids
3218
3219
3221 """Generate a list of spin ID variants to eliminate for the given set of molecule, residue and spin indices.
3222
3223 @keyword dp: The data pipe to work on.
3224 @type dp: PipeContainer instance
3225 @keyword mol_index: The molecule index.
3226 @type mol_index: int
3227 @keyword res_index: The residue index.
3228 @type res_index: int
3229 @keyword spin_index: The spin index.
3230 @type spin_index: int
3231 @return: The list of all spin IDs matching the spin.
3232 @rtype: list of str
3233 """
3234
3235
3236 spin_ids = []
3237 mol = dp.mol[mol_index]
3238 res = dp.mol[mol_index].res[res_index]
3239 spin = dp.mol[mol_index].res[res_index].spin[spin_index]
3240 mol_count = len(dp.mol)
3241 res_count = len(mol.res)
3242 spin_count = len(res.spin)
3243
3244
3245 spin_ids.append(generate_spin_id(mol_name=mol.name, res_num=res.num, res_name=res.name, spin_num=spin.num, spin_name=spin.name))
3246
3247
3248 if spin_count > 1:
3249 spin_ids.append(generate_spin_id(mol_name=mol.name, res_num=res.num, res_name=res.name))
3250
3251
3252 if res_count > 1:
3253 spin_ids.append(generate_spin_id(mol_name=mol.name, spin_num=spin.num, spin_name=spin.name))
3254
3255
3256 if mol_count > 1:
3257 spin_ids.append(generate_spin_id(res_num=res.num, res_name=res.name, spin_num=spin.num, spin_name=spin.name))
3258
3259
3260 if spin_count > 1 and res_count > 1:
3261 spin_ids.append(generate_spin_id(mol_name=mol.name))
3262
3263
3264 if spin_count > 1 and mol_count > 1:
3265 spin_ids.append(generate_spin_id(res_num=res.num, res_name=res.name))
3266
3267
3268 if res_count > 1 and mol_count > 1:
3269 spin_ids.append(generate_spin_id(spin_num=spin.num, spin_name=spin.name))
3270
3271
3272 return spin_ids
3273
3274
3275 -def spin_in_list(spin_list, mol_name_col=None, res_num_col=None, res_name_col=None, spin_num_col=None, spin_name_col=None, mol_name=None, res_num=None, res_name=None, spin_num=None, spin_name=None):
3276 """Function for determining if the spin is located within the list of spins.
3277
3278 @param spin_list: The list of spins. The first dimension corresponds to different spins,
3279 the second corresponds to the spin information columns.
3280 @type spin_list: list of lists of str
3281 @keyword mol_name_col: The column containing the molecule name information.
3282 @type mol_name_col: int or None
3283 @keyword res_num_col: The column containing the residue number information.
3284 @type res_num_col: int or None
3285 @keyword res_name_col: The column containing the residue name information.
3286 @type res_name_col: int or None
3287 @keyword spin_num_col: The column containing the spin number information.
3288 @type spin_num_col: int or None
3289 @keyword spin_name_col: The column containing the spin name information.
3290 @type spin_name_col: int or None
3291 @keyword mol_name: The molecule name.
3292 @type mol_name: str or None
3293 @keyword res_num: The residue number.
3294 @type res_num: int or None
3295 @keyword res_name: The residue name.
3296 @type res_name: str or None
3297 @keyword spin_num: The spin number.
3298 @type spin_num: int or None
3299 @keyword spin_name: The spin name.
3300 @type spin_name: str or None
3301 @return: The answer of whether the spin is within the list.
3302 @rtype: bool
3303 """
3304
3305
3306 select_obj = Selection(generate_spin_id(mol_name=mol_name, res_num=res_num, res_name=res_name, spin_num=spin_num, spin_name=spin_name))
3307
3308
3309 for spin in spin_list:
3310
3311 spin_id = generate_spin_id_data_array(data=file_data[i], mol_name_col=mol_name_col, res_num_col=res_num_col, res_name_col=res_name_col, spin_num_col=spin_num_col, spin_name_col=spin_name_col)
3312
3313
3314 if spin_id in select_obj:
3315 return True
3316
3317
3318 return False
3319
3320
3322 """Generator function for looping over all selected spins, returning the mol-res-spin indices.
3323
3324 @param selection: The spin system selection identifier.
3325 @type selection: str
3326 @param pipe: The data pipe containing the spin. Defaults to the current data pipe.
3327 @type pipe: str
3328 @return: The molecule, residue, and spin index.
3329 @rtype: tuple of 3 int
3330 """
3331
3332
3333 if pipe == None:
3334 pipe = pipes.cdp_name()
3335
3336
3337 pipes.test(pipe)
3338
3339
3340 dp = pipes.get_pipe(pipe)
3341
3342
3343 if not exists_mol_res_spin_data(pipe=pipe):
3344 return
3345
3346
3347 select_obj = Selection(selection)
3348
3349
3350 for mol_index in range(len(dp.mol)):
3351
3352 mol = dp.mol[mol_index]
3353
3354
3355 for res_index in range(len(dp.mol[mol_index].res)):
3356
3357 res = dp.mol[mol_index].res[res_index]
3358
3359
3360 for spin_index in range(len(dp.mol[mol_index].res[res_index].spin)):
3361
3362 spin = dp.mol[mol_index].res[res_index].spin[spin_index]
3363
3364
3365 if (mol, res, spin) not in select_obj:
3366 continue
3367
3368
3369 yield mol_index, res_index, spin_index
3370
3371
3372 -def spin_loop(selection=None, pipe=None, full_info=False, return_id=False):
3373 """Generator function for looping over all the spin systems of the given selection.
3374
3375 @keyword selection: The spin system selection identifier.
3376 @type selection: str
3377 @keyword pipe: The data pipe containing the spin. Defaults to the current data pipe.
3378 @type pipe: str
3379 @keyword full_info: A flag which if True will cause the the molecule name, residue number, and residue name to be returned in addition to the spin container.
3380 @type full_info: bool
3381 @keyword return_id: A flag which if True will cause the spin identification string of the current spin to be returned in addition to the spin container.
3382 @type return_id: bool
3383 @return: The spin system specific data container. If full_info is True, a tuple of the spin container, the molecule name, residue number, and residue name. If return_id is True, a tuple of the spin container and spin id. If both flags are True, then a tuple of the spin container, the molecule name, residue number, residue name, and spin id.
3384 @rtype: If full_info and return_id are False, SpinContainer instance. If full_info is True and return_id is false, a tuple of (SpinContainer instance, str, int, str). If full_info is False and return_id is True, a tuple of (SpinContainer instance, str). If full_info and return_id are False, a tuple of (SpinContainer instance, str, int, str, str)
3385 """
3386
3387
3388 if pipe == None:
3389 pipe = pipes.cdp_name()
3390
3391
3392 pipes.test(pipe)
3393
3394
3395 dp = pipes.get_pipe(pipe)
3396
3397
3398 if not exists_mol_res_spin_data(pipe=pipe):
3399 return
3400
3401
3402 select_obj = Selection(selection)
3403
3404
3405 for mol in dp.mol:
3406
3407 for res in mol.res:
3408
3409 for spin in res.spin:
3410
3411 if (mol, res, spin) not in select_obj:
3412 continue
3413
3414
3415 if return_id:
3416 spin_id = generate_spin_id(mol.name, res.num, res.name, spin.num, spin.name)
3417
3418
3419 if full_info and return_id:
3420 yield spin, mol.name, res.num, res.name, spin_id
3421 elif full_info:
3422 yield spin, mol.name, res.num, res.name
3423 elif return_id:
3424 yield spin, spin_id
3425 else:
3426 yield spin
3427
3428
3430 """Split the input selection string returning the mol_token, res_token, and spin_token strings.
3431
3432 The mol_token is identified as the text from the '#' to either the ':' or '@' characters or the
3433 end of the string.
3434
3435 The res_token is identified as the text from the ':' to either the '@' character or the end of
3436 the string.
3437
3438 The spin_token is identified as the text from the '@' to the end of the string.
3439
3440 @param selection: The selection identifier.
3441 @type selection: str
3442 @return: The mol_token, res_token, and spin_token.
3443 @rtype: 3-tuple of str or None
3444 """
3445
3446
3447 if selection == None:
3448 return None, None, None
3449
3450
3451
3452 mol_info = ''
3453 res_info = ''
3454 spin_info = ''
3455 pos = 'mol'
3456 for i in range(len(selection)):
3457
3458 if selection[i] == '|':
3459 raise RelaxError("The boolean operator '|' is not supported for individual spin selections.")
3460
3461
3462 if selection[i] == ':':
3463 if pos == 'spin':
3464 raise RelaxError("Invalid selection string '%s'." % selection)
3465 pos = 'res'
3466
3467
3468 if selection[i] == '@':
3469 pos = 'spin'
3470
3471
3472 if pos == 'mol':
3473 mol_info = mol_info + selection[i]
3474 if pos == 'res':
3475 res_info = res_info + selection[i]
3476 if pos == 'spin':
3477 spin_info = spin_info + selection[i]
3478
3479
3480
3481
3482
3483
3484 if mol_info:
3485
3486 if '&' in mol_info:
3487 raise RelaxError("The boolean operator '&' is not supported for the molecule component of individual spin IDs.")
3488
3489
3490
3491
3492
3493
3494 if ':' in mol_info or '@' in mol_info or mol_info[0] != '#' or mol_info.count('#') != 1:
3495 raise RelaxError("Invalid molecule selection '%s'." % mol_info)
3496
3497
3498 mol_token = mol_info[1:]
3499
3500
3501 else:
3502 mol_token = None
3503
3504
3505
3506
3507
3508
3509 if res_info:
3510
3511 if res_info.count('&') > 1:
3512 raise RelaxError("Only one '&' boolean operator is supported for the residue component of individual spin IDs.")
3513
3514
3515 res_token = split('&', res_info)
3516
3517
3518 for i in range(len(res_token)):
3519
3520
3521
3522
3523
3524 if '#' in res_token[i] or '@' in res_token[i] or res_token[i][0] != ':' or res_token[i].count(':') != 1:
3525 raise RelaxError("Invalid residue selection '%s'." % res_info)
3526
3527
3528 res_token[i] = res_token[i][1:]
3529
3530
3531 if len(res_token) == 1:
3532 res_token = res_token[0]
3533
3534
3535 else:
3536 res_token = None
3537
3538
3539
3540
3541
3542
3543 if spin_info:
3544
3545 if spin_info.count('&') > 1:
3546 raise RelaxError("Only one '&' boolean operator is supported for the spin component of individual spin IDs.")
3547
3548
3549 spin_token = split('&', spin_info)
3550
3551
3552 for i in range(len(spin_token)):
3553
3554
3555
3556
3557
3558 if '#' in spin_token[i] or ':' in spin_token[i] or spin_token[i][0] != '@' or spin_token[i].count('@') != 1:
3559 raise RelaxError("Invalid spin selection '%s'." % spin_info)
3560
3561
3562 spin_token[i] = spin_token[i][1:]
3563
3564
3565 if len(spin_token) == 1:
3566 spin_token = spin_token[0]
3567
3568
3569 else:
3570 spin_token = None
3571
3572
3573
3574
3575
3576
3577 if mol_token == None and res_token == None and spin_token == None:
3578 raise RelaxError("The selection string '%s' is invalid." % selection)
3579
3580
3581 return mol_token, res_token, spin_token
3582
3583
3585 """Set the molecule type.
3586
3587 @param mol_id: The molecule identification string.
3588 @type mol_id: str
3589 @param type: The molecule type.
3590 @type type: str
3591 @keyword force: A flag which if True will cause the molecule type to be overwritten.
3592 @type force: bool
3593 """
3594
3595
3596 if type not in ALLOWED_MOL_TYPES:
3597 raise RelaxError("The molecule type '%s' must be one of %s." % (type, ALLOWED_MOL_TYPES))
3598
3599
3600 select_obj = Selection(mol_id)
3601 if select_obj.has_residues():
3602 raise RelaxResSelectDisallowError
3603 if select_obj.has_spins():
3604 raise RelaxSpinSelectDisallowError
3605
3606
3607 for mol in molecule_loop(mol_id):
3608 if hasattr(mol, 'type') and mol.type and not force:
3609 warn(RelaxWarning("The molecule '%s' already has its type set. Set the force flag to change." % mol_id))
3610 else:
3611 mol.type = type
3612