1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 """The molecule-residue-spin containers of the relax data store."""
25
26
27 from binascii import hexlify
28 from os import urandom
29 from re import match
30
31
32 from data_store.prototype import Prototype
33 from lib.errors import RelaxError, RelaxFromXMLNotEmptyError, RelaxImplementError
34 from lib.xml import fill_object_contents, object_to_xml, xml_to_object
35 import specific_analyses
36
37
38
39
40
42 """Class containing all the spin system specific data."""
43
44 - def __init__(self, spin_name=None, spin_num=None, select=True):
45 """Set up the default objects of the spin system data container.
46
47 @keyword spin_name: The name of the spin.
48 @type spin_name: str or None
49 @keyword spin_num: The number of the spin.
50 @type spin_num: str or None
51 @keyword select: The selection flag.
52 @type select: bool
53 """
54
55
56 self.name = spin_name
57 self.num = spin_num
58 self.select = select
59
60
61 self._generate_hash()
62
63
64 self._interatomic_hashes = []
65
66
67 self._mol_name = None
68 self._mol_index = None
69 self._res_name = None
70 self._res_num = None
71 self._res_index = None
72 self._spin_index = None
73 self._spin_ids = []
74
75
77 """The string representation of the object.
78
79 Rather than using the standard Python conventions (either the string representation of the
80 value or the "<...desc...>" notation), a rich-formatted description of the object is given.
81 """
82
83
84 text = "Class containing all the spin system specific data.\n\n"
85
86
87 text = text + "\n"
88 text = text + "Objects:\n"
89 for name in dir(self):
90
91 if name == 'is_empty':
92 continue
93
94
95 if name not in ['_spin_ids', '_hash'] and match("^_", name):
96 continue
97
98
99 text = text + " " + name + ": " + repr(getattr(self, name)) + "\n"
100
101 return text
102
103
105 """Method for converting old spin data structures to the new ones.
106
107 @keyword file_version: The relax XML version of the XML file.
108 @type file_version: int
109 """
110
111
112 if hasattr(self, 'equation') and self.equation in ['mf_orig', 'mf_ext', 'mf_ext2']:
113 self._back_compat_hook_mf_data()
114
115
116 self._back_compat_hook_ri_data()
117
118
120 """Converting the old model-free parameter vector to the new one."""
121
122
123 if not hasattr(self, 'params'):
124 return
125
126
127 for i in range(len(self.params)):
128 self.params[i] = self.params[i].lower()
129
130
132 """Converting the old spin relaxation data structures to the new ones."""
133
134
135 if not (hasattr(self, 'frq_labels') and hasattr(self, 'noe_r1_table') and hasattr(self, 'remap_table')):
136 return
137
138
139 self.ri_data = {}
140 self.ri_data_err = {}
141 sims = False
142 if hasattr(self, 'relax_sim_data'):
143 sims = True
144 self.ri_data_sim = {}
145
146
147 for i in range(self.num_ri):
148
149 ri_id = "%s_%s" % (self.ri_labels[i], self.frq_labels[self.remap_table[i]])
150
151
152 self.ri_data[ri_id] = self.relax_data[i]
153 self.ri_data_err[ri_id] = self.relax_error[i]
154
155
156 if sims:
157 self.ri_data_sim[ri_id] = []
158 for j in range(cdp.sim_number):
159 self.ri_data_sim[ri_id].append(self.relax_sim_data[j][i])
160
161
162 del self.frq
163 del self.frq_labels
164 del self.noe_r1_table
165 del self.num_frq
166 del self.num_ri
167 del self.ri_labels
168 del self.remap_table
169 del self.relax_data
170 del self.relax_error
171 if sims:
172 del self.relax_sim_data
173
174
176 """Generate a unique hash for the spin."""
177
178
179 self._hash = hexlify(urandom(20))
180
181
183 """Method for testing if this SpinContainer object is empty.
184
185 @return: True if this container is empty and the spin number and name have not been set,
186 False otherwise.
187 @rtype: bool
188 """
189
190
191 if self.num != None or self.name != None:
192 return False
193
194
195 for name in dir(self):
196
197 if name == 'num' or name == 'name' or name == 'select':
198 continue
199
200
201 if name == 'is_empty':
202 continue
203
204
205 if match("^_", name):
206 continue
207
208
209 return False
210
211
212 return True
213
214
216 """List type data container for spin system specific data."""
217
219 """Set up the first spin system data container."""
220
221
222 self.append(SpinContainer())
223
224
226 """The string representation of the object.
227
228 Rather than using the standard Python conventions (either the string representation of the
229 value or the "<...desc...>" notation), a rich-formatted description of the object is given.
230 """
231
232
233 text = "Spin systems.\n\n"
234
235
236 text = text + "%-8s%-8s%-8s%-10s" % ("Index", "Number", "Name", "Selected") + "\n"
237 for i in range(len(self)):
238 text = text + "%-8i%-8s%-8s%-10s" % (i, repr(self[i].num), self[i].name, self[i].select) + "\n"
239 text = text + "\nThese can be accessed by typing 'D.mol[i].res[j].spin[k]', where D is the relax data storage object.\n"
240
241 return text
242
243
244 - def add_item(self, spin_name=None, spin_num=None, select=True):
245 """Appending an empty container to the list.
246
247 @keyword spin_name: The name of the new spin.
248 @type spin_name: str or None
249 @keyword spin_num: The number of the new spin.
250 @type spin_num: str or None
251 @keyword select: The selection flag.
252 @type select: bool
253 @return: The new container.
254 @rtype: SpinContainer instance
255 """
256
257
258 if self.is_empty():
259 self[0].num = spin_num
260 self[0].name = spin_name
261 self[0].select = select
262
263
264 return self[0]
265
266
267 else:
268
269 for i in range(len(self)):
270
271 if spin_num != None and spin_name != None:
272 if self[i].num == spin_num and self[i].name == spin_name:
273 raise RelaxError("The spin with name '%s' and number '%s' already exists." % (spin_name, spin_num))
274
275
276 if spin_num == None and self[i].name == spin_name:
277 raise RelaxError("The unnumbered spin name '%s' already exists." % spin_name)
278
279
280 self.append(SpinContainer(spin_name, spin_num, select))
281
282
283 return self[-1]
284
285
287 """Method for testing if this SpinList object is empty.
288
289 @return: True if this list only has one SpinContainer and the spin number and name have
290 not been set, False otherwise.
291 @rtype: bool
292 """
293
294
295 if len(self) == 1 and self[0].is_empty():
296 return True
297
298
299 return False
300
301
302 - def from_xml(self, spin_nodes, file_version=None):
303 """Recreate a spin list data structure from the XML spin nodes.
304
305 @param spin_nodes: The spin XML nodes.
306 @type spin_nodes: xml.dom.minicompat.NodeList instance
307 @keyword file_version: The relax XML version of the XML file.
308 @type file_version: int
309 """
310
311
312 if not self.is_empty():
313 raise RelaxFromXMLNotEmptyError(self.__class__.__name__)
314
315
316 for spin_node in spin_nodes:
317
318 name = str(spin_node.getAttribute('name'))
319 if name == 'None':
320 name = None
321 num = eval(spin_node.getAttribute('num'))
322
323
324 self.add_item(spin_name=name, spin_num=num)
325
326
327 xml_to_object(spin_node, self[-1], file_version=file_version)
328
329
330 self[-1]._back_compat_hook(file_version)
331
332
333 - def to_xml(self, doc, element, pipe_type=None):
334 """Create XML elements for each spin.
335
336 @param doc: The XML document object.
337 @type doc: xml.dom.minidom.Document instance
338 @param element: The element to add the spin XML elements to.
339 @type element: XML element object
340 @keyword pipe_type: The type of the pipe being converted to XML.
341 @type pipe_type: str
342 """
343
344
345 api = specific_analyses.api.return_api(analysis_type=pipe_type)
346
347
348 for i in range(len(self)):
349
350 spin_element = doc.createElement('spin')
351 element.appendChild(spin_element)
352
353
354 spin_element.setAttribute('desc', 'Spin container')
355 spin_element.setAttribute('name', str(self[i].name))
356 spin_element.setAttribute('num', str(self[i].num))
357
358
359 object_info = []
360 try:
361 for name in api.data_names(error_names=True, sim_names=True):
362
363 if hasattr(api, 'return_data_desc'):
364 desc = api.return_data_desc(name)
365 else:
366 desc = None
367
368
369 object_info.append([name, desc])
370 except RelaxImplementError:
371 pass
372
373
374 blacklist = []
375 for name, desc in object_info:
376
377 blacklist.append(name)
378
379
380 if not hasattr(self[i], name):
381 continue
382
383
384 sub_element = doc.createElement(name)
385 spin_element.appendChild(sub_element)
386
387
388 if desc:
389 sub_element.setAttribute('desc', desc)
390
391
392 object = getattr(self[i], name)
393
394
395 object_to_xml(doc, sub_element, value=object)
396
397
398 fill_object_contents(doc, spin_element, object=self[i], blacklist=['name', 'num', 'spin'] + blacklist + list(self[i].__class__.__dict__.keys()))
399
400
401
402
403
404
406 """Class containing all the residue specific data."""
407
408 - def __init__(self, res_name=None, res_num=None):
409 """Set up the default objects of the residue data container."""
410
411
412 self.name = res_name
413 self.num = res_num
414
415
416 self._mol_name = None
417 self._mol_index = None
418 self._res_index = None
419
420
421 self.spin = SpinList()
422
423
425 """The string representation of the object.
426
427 Rather than using the standard Python conventions (either the string representation of the
428 value or the "<...desc...>" notation), a rich-formatted description of the object is given.
429 """
430
431
432 text = "Class containing all the residue specific data.\n"
433
434
435 text = text + "\n"
436 text = text + "Objects:\n"
437 for name in dir(self):
438
439 if name == 'spin':
440 text = text + " spin: The list of spin systems of the residues\n"
441 continue
442
443
444 if name == 'is_empty':
445 continue
446
447
448 if match("^_", name):
449 continue
450
451
452 text = text + " " + name + ": " + repr(getattr(self, name)) + "\n"
453
454 return text
455
456
458 """Method for testing if this ResidueContainer object is empty.
459
460 @return: True if this container is empty and the residue number and name have not been
461 set, False otherwise.
462 @rtype: bool
463 """
464
465
466 if self.num != None or self.name != None:
467 return False
468
469
470 for name in dir(self):
471
472 if name == 'num' or name == 'name' or name == 'spin':
473 continue
474
475
476 if name == 'is_empty':
477 continue
478
479
480 if match("^_", name):
481 continue
482
483
484 return False
485
486
487 if not self.spin.is_empty():
488 return False
489
490
491 return True
492
493
495 """List type data container for residue specific data."""
496
502
503
505 """The string representation of the object.
506
507 Rather than using the standard Python conventions (either the string representation of the
508 value or the "<...desc...>" notation), a rich-formatted description of the object is given.
509 """
510
511
512 text = "Residues.\n\n"
513
514
515 text = text + "%-8s%-8s%-8s" % ("Index", "Number", "Name") + "\n"
516 for i in range(len(self)):
517 text = text + "%-8i%-8s%-8s" % (i, repr(self[i].num), self[i].name) + "\n"
518 text = text + "\nThese can be accessed by typing 'D.mol[i].res[j]', where D is the relax data storage object.\n"
519
520 return text
521
522
523 - def add_item(self, res_name=None, res_num=None):
524 """Append an empty ResidueContainer to the ResidueList."""
525
526
527 if self.is_empty():
528 self[0].num = res_num
529 self[0].name = res_name
530
531
532 else:
533
534 for i in range(len(self)):
535
536 if res_num != None:
537 if self[i].num == res_num:
538 raise RelaxError("The residue number '" + repr(res_num) + "' already exists in the sequence.")
539
540
541 else:
542 if self[i].name == res_name:
543 raise RelaxError("The unnumbered residue name '" + repr(res_name) + "' already exists.")
544
545
546 self.append(ResidueContainer(res_name, res_num))
547
548
550 """Method for testing if this ResidueList object is empty.
551
552 @return: True if this list only has one ResidueContainer and the residue number and name
553 have not been set, False otherwise.
554 @rtype: bool
555 """
556
557
558 if len(self) == 1 and self[0].is_empty():
559 return True
560
561
562 return False
563
564
565 - def from_xml(self, res_nodes, file_version=None):
566 """Recreate a residue list data structure from the XML residue nodes.
567
568 @param res_nodes: The residue XML nodes.
569 @type res_nodes: xml.dom.minicompat.NodeList instance
570 @keyword file_version: The relax XML version of the XML file.
571 @type file_version: int
572 """
573
574
575 if not self.is_empty():
576 raise RelaxFromXMLNotEmptyError(self.__class__.__name__)
577
578
579 for res_node in res_nodes:
580
581 name = str(res_node.getAttribute('name'))
582 if name == 'None':
583 name = None
584 num = eval(res_node.getAttribute('num'))
585 self.add_item(res_name=name, res_num=num)
586
587
588 spin_nodes = res_node.getElementsByTagName('spin')
589
590
591 self[-1].spin.from_xml(spin_nodes, file_version=file_version)
592
593
594 - def to_xml(self, doc, element, pipe_type=None):
595 """Create XML elements for each residue.
596
597 @param doc: The XML document object.
598 @type doc: xml.dom.minidom.Document instance
599 @param element: The element to add the residue XML elements to.
600 @type element: XML element object
601 @keyword pipe_type: The type of the pipe being converted to XML.
602 @type pipe_type: str
603 """
604
605
606 for i in range(len(self)):
607
608 res_element = doc.createElement('res')
609 element.appendChild(res_element)
610
611
612 res_element.setAttribute('desc', 'Residue container')
613 res_element.setAttribute('name', str(self[i].name))
614 res_element.setAttribute('num', str(self[i].num))
615
616
617 fill_object_contents(doc, res_element, object=self[i], blacklist=['name', 'num', 'spin'] + list(self[i].__class__.__dict__.keys()))
618
619
620 self[i].spin.to_xml(doc, res_element, pipe_type=pipe_type)
621
622
623
624
625
626
628 """Class containing all the molecule specific data."""
629
630 - def __init__(self, mol_name=None, mol_type=None):
631 """Set up the default objects of the molecule data container."""
632
633
634 self.name = mol_name
635
636
637 self.type = mol_type
638
639
640 self._mol_index = None
641
642
643 self.res = ResidueList()
644
645
647 """The string representation of the object.
648
649 Rather than using the standard Python conventions (either the string representation of the
650 value or the "<...desc...>" notation), a rich-formatted description of the object is given.
651 """
652
653
654 text = "Class containing all the molecule specific data.\n"
655
656
657 text = text + "\n"
658 text = text + "Objects:\n"
659 for name in dir(self):
660
661 if name == 'res':
662 text = text + " res: The list of the residues of the molecule\n"
663 continue
664
665
666 if name == 'is_empty':
667 continue
668
669
670 if match("^_", name):
671 continue
672
673
674 text = text + " " + name + ": " + repr(getattr(self, name)) + "\n"
675
676 return text
677
678
680 """Method for testing if this MoleculeContainer object is empty.
681
682 @return: True if this container is empty and the molecule name has not been set, False
683 otherwise.
684 @rtype: bool
685 """
686
687
688 if self.name != None:
689 return False
690
691
692 for name in dir(self):
693
694 if name in ['name', 'res', 'type']:
695 continue
696
697
698 if name == 'is_empty':
699 continue
700
701
702 if match("^_", name):
703 continue
704
705
706 return False
707
708
709 if not self.res.is_empty():
710 return False
711
712
713 return True
714
715
717 """List type data container for the molecule specific data."""
718
720 """Set up the first molecule data container."""
721
722
723 self.append(MoleculeContainer())
724
725
726 self._spin_id_lookup = {}
727 self._spin_hash_lookup = {}
728
729
731 """The string representation of the object.
732
733 Rather than using the standard Python conventions (either the string representation of the
734 value or the "<...desc...>" notation), a rich-formatted description of the object is given.
735 """
736
737 text = "Molecules.\n\n"
738 text = text + "%-8s%-8s" % ("Index", "Name") + "\n"
739 for i in range(len(self)):
740 text = text + "%-8i%-8s" % (i, self[i].name) + "\n"
741 text = text + "\nThese can be accessed by typing 'D.mol[i]', where D is the relax data storage object.\n"
742 return text
743
744
745 - def add_item(self, mol_name=None, mol_type=None):
746 """Append an empty MoleculeContainer to the MoleculeList."""
747
748
749 if self.is_empty():
750 self[0].name = mol_name
751 self[0].type = mol_type
752
753
754 else:
755
756 for i in range(len(self)):
757 if self[i].name == mol_name:
758 raise RelaxError("The molecule '%s' already exists in the sequence." % mol_name)
759
760
761 self.append(MoleculeContainer(mol_name, mol_type))
762
763
765 """Method for testing if this MoleculeList object is empty.
766
767 @return: True if this list only has one MoleculeContainer and the molecule name has not
768 been set, False otherwise.
769 @rtype: bool
770 """
771
772
773 if len(self) == 1 and self[0].is_empty():
774 return True
775
776
777 return False
778
779
780 - def from_xml(self, mol_nodes, file_version=None):
781 """Recreate a molecule list data structure from the XML molecule nodes.
782
783 @param mol_nodes: The molecule XML nodes.
784 @type mol_nodes: xml.dom.minicompat.NodeList instance
785 @keyword file_version: The relax XML version of the XML file.
786 @type file_version: int
787 """
788
789
790 if not self.is_empty():
791 raise RelaxFromXMLNotEmptyError(self.__class__.__name__)
792
793
794 for mol_node in mol_nodes:
795
796 name = str(mol_node.getAttribute('name'))
797 if name == 'None':
798 name = None
799 type = str(mol_node.getAttribute('type'))
800 if type == 'None':
801 type = None
802 self.add_item(mol_name=name, mol_type=type)
803
804
805 res_nodes = mol_node.getElementsByTagName('res')
806
807
808 self[-1].res.from_xml(res_nodes, file_version=file_version)
809
810
811 - def to_xml(self, doc, element, pipe_type=None):
812 """Create XML elements for each molecule.
813
814 @param doc: The XML document object.
815 @type doc: Xml.dom.minidom.Document instance
816 @param element: The element to add the molecule XML elements to.
817 @type element: XML element object
818 @keyword pipe_type: The type of the pipe being converted to XML.
819 @type pipe_type: str
820 """
821
822
823 for i in range(len(self)):
824
825 mol_element = doc.createElement('mol')
826 element.appendChild(mol_element)
827
828
829 mol_element.setAttribute('desc', 'Molecule container')
830 mol_element.setAttribute('name', str(self[i].name))
831 mol_element.setAttribute('type', str(self[i].type))
832
833
834 fill_object_contents(doc, mol_element, object=self[i], blacklist=['name', 'res', 'type'] + list(self[i].__class__.__dict__.keys()))
835
836
837 self[i].res.to_xml(doc, mol_element, pipe_type=pipe_type)
838