Package data :: Module mol_res_spin
[hide private]
[frames] | no frames]

Source Code for Module data.mol_res_spin

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2007-2012 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax.                                     # 
  6  #                                                                             # 
  7  # relax is free software; you can redistribute it and/or modify               # 
  8  # it under the terms of the GNU General Public License as published by        # 
  9  # the Free Software Foundation; either version 2 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # relax is distributed in the hope that it will be useful,                    # 
 13  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 14  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 15  # GNU General Public License for more details.                                # 
 16  #                                                                             # 
 17  # You should have received a copy of the GNU General Public License           # 
 18  # along with relax; if not, write to the Free Software                        # 
 19  # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA   # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23  # Module docstring. 
 24  """The molecule-residue-spin containers.""" 
 25   
 26  # Python module imports. 
 27  import numpy 
 28  from re import match 
 29  from string import lower 
 30   
 31  # relax module imports. 
 32  from float import floatAsByteArray 
 33  import generic_fns 
 34  from prototype import Prototype 
 35  from relax_errors import RelaxError, RelaxFromXMLNotEmptyError, RelaxImplementError 
 36  from relax_xml import fill_object_contents, xml_to_object 
 37  import specific_fns 
 38   
 39   
 40  # The spin system data. 
 41  ####################### 
 42   
43 -class SpinContainer(Prototype):
44 """Class containing all the spin system specific data.""" 45
46 - def __init__(self, spin_name=None, spin_num=None, select=True):
47 """Set up the default objects of the spin system data container.""" 48 49 # The spin system name and number. 50 self.name = spin_name 51 self.num = spin_num 52 self.select = select
53 54
55 - def __repr__(self):
56 """The string representation of the object. 57 58 Rather than using the standard Python conventions (either the string representation of the 59 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 60 """ 61 62 # Intro. 63 text = "Class containing all the spin system specific data.\n\n" 64 65 # Objects. 66 text = text + "\n" 67 text = text + "Objects:\n" 68 for name in dir(self): 69 # Skip the SpinContainer methods. 70 if name == 'is_empty': 71 continue 72 73 # Skip special objects. 74 if match("^_", name): 75 continue 76 77 # Add the object's attribute to the text string. 78 text = text + " " + name + ": " + repr(getattr(self, name)) + "\n" 79 80 return text
81 82
83 - def _back_compat_hook(self, file_version=None):
84 """Method for converting old spin data structures to the new ones. 85 86 @keyword file_version: The relax version used to create the XML file. 87 @type file_version: str 88 """ 89 90 # Model-free parameters. 91 self._back_compat_hook_mf_data() 92 93 # Relaxation data. 94 self._back_compat_hook_ri_data()
95 96
98 """Converting the old model-free parameter vector to the new one.""" 99 100 # Nothing to do. 101 if not hasattr(self, 'params'): 102 return 103 104 # Loop over the parameters, converting them to lowercase. 105 for i in range(len(self.params)): 106 self.params[i] = lower(self.params[i])
107 108
110 """Converting the old spin relaxation data structures to the new ones.""" 111 112 # Nothing to do. 113 if not (hasattr(self, 'frq_labels') and hasattr(self, 'noe_r1_table') and hasattr(self, 'remap_table')): 114 return 115 116 # Initialise the new structures. 117 self.ri_data = {} 118 self.ri_data_err = {} 119 sims = False 120 if hasattr(self, 'relax_sim_data'): 121 sims = True 122 self.ri_data_sim = {} 123 124 # Generate the new structures. 125 for i in range(self.num_ri): 126 # The ID. 127 ri_id = "%s_%s" % (self.ri_labels[i], self.frq_labels[self.remap_table[i]]) 128 129 # The relaxation data. 130 self.ri_data[ri_id] = self.relax_data[i] 131 self.ri_data_err[ri_id] = self.relax_error[i] 132 133 # Simulation data. 134 if sims: 135 self.ri_data_sim[ri_id] = [] 136 for j in range(cdp.sim_number): 137 self.ri_data_sim[ri_id].append(self.relax_sim_data[j][i]) 138 139 140 # Delete the old structures. 141 del self.frq 142 del self.frq_labels 143 del self.noe_r1_table 144 del self.num_frq 145 del self.num_ri 146 del self.ri_labels 147 del self.remap_table 148 del self.relax_data 149 del self.relax_error 150 if sims: 151 del self.relax_sim_data
152 153
154 - def is_empty(self):
155 """Method for testing if this SpinContainer object is empty. 156 157 @return: True if this container is empty and the spin number and name have not been set, 158 False otherwise. 159 @rtype: bool 160 """ 161 162 # The spin number or spin name has been set. 163 if self.num != None or self.name != None: 164 return False 165 166 # An object has been added to the container. 167 for name in dir(self): 168 # Skip the objects initialised in __init__(). 169 if name == 'num' or name == 'name' or name == 'select': 170 continue 171 172 # Skip the SpinContainer methods. 173 if name == 'is_empty': 174 continue 175 176 # Skip special objects. 177 if match("^_", name): 178 continue 179 180 # An object has been added. 181 return False 182 183 # The SpinContainer is unmodified. 184 return True
185 186
187 -class SpinList(list):
188 """List type data container for spin system specific data.""" 189
190 - def __init__(self):
191 """Set up the first spin system data container.""" 192 193 # Add the initial spin system container at index 0. 194 self.append(SpinContainer())
195 196
197 - def __repr__(self):
198 """The string representation of the object. 199 200 Rather than using the standard Python conventions (either the string representation of the 201 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 202 """ 203 204 # Intro. 205 text = "Spin systems.\n\n" 206 207 # Residue data. 208 text = text + "%-8s%-8s%-8s%-10s" % ("Index", "Number", "Name", "Selected") + "\n" 209 for i in xrange(len(self)): 210 text = text + "%-8i%-8s%-8s%-10s" % (i, repr(self[i].num), self[i].name, self[i].select) + "\n" 211 text = text + "\nThese can be accessed by typing 'D.mol[i].res[j].spin[k]', where D is the relax data storage object.\n" 212 213 return text
214 215
216 - def add_item(self, spin_name=None, spin_num=None, select=True):
217 """Function for appending an empty container to the list.""" 218 219 # If no spin data exists, replace the empty first spin with this spin. 220 if self.is_empty(): 221 self[0].num = spin_num 222 self[0].name = spin_name 223 self[0].select = select 224 225 # Otherwise append a new SpinContainer. 226 else: 227 # Test if the spin number (or name if unnumbered) already exists. 228 for i in xrange(len(self)): 229 # Spin number has been supplied. 230 if spin_num != None: 231 if self[i].num == spin_num: 232 raise RelaxError("The spin number '" + repr(spin_num) + "' already exists.") 233 234 # No spin numbers. 235 else: 236 if self[i].name == spin_name: 237 raise RelaxError("The unnumbered spin name '" + repr(spin_name) + "' already exists.") 238 239 # Append a new SpinContainer. 240 self.append(SpinContainer(spin_name, spin_num, select))
241 242
243 - def is_empty(self):
244 """Method for testing if this SpinList object is empty. 245 246 @return: True if this list only has one SpinContainer and the spin number and name have 247 not been set, False otherwise. 248 @rtype: bool 249 """ 250 251 # There is only one SpinContainer and it is empty. 252 if len(self) == 1 and self[0].is_empty(): 253 return True 254 255 # Otherwise. 256 return False
257 258
259 - def from_xml(self, spin_nodes, file_version=None):
260 """Recreate a spin list data structure from the XML spin nodes. 261 262 @param spin_nodes: The spin XML nodes. 263 @type spin_nodes: xml.dom.minicompat.NodeList instance 264 @keyword file_version: The relax version used to create the XML file. 265 @type file_version: str 266 """ 267 268 # Test if empty. 269 if not self.is_empty(): 270 raise RelaxFromXMLNotEmptyError(self.__class__.__name__) 271 272 # Loop over the spins. 273 for spin_node in spin_nodes: 274 # Get the spin details and add the spin to the SpinList structure. 275 name = str(spin_node.getAttribute('name')) 276 if name == 'None': 277 name = None 278 num = eval(spin_node.getAttribute('num')) 279 self.add_item(spin_name=name, spin_num=num) 280 281 # Recreate the current spin container. 282 xml_to_object(spin_node, self[-1]) 283 284 # Backwards compatibility transformations. 285 self[-1]._back_compat_hook(file_version)
286 287
288 - def to_xml(self, doc, element):
289 """Create XML elements for each spin. 290 291 @param doc: The XML document object. 292 @type doc: xml.dom.minidom.Document instance 293 @param element: The element to add the spin XML elements to. 294 @type element: XML element object 295 """ 296 297 # Get the specific functions. 298 data_names = specific_fns.setup.get_specific_fn('data_names', generic_fns.pipes.get_type(), raise_error=False) 299 return_data_desc = specific_fns.setup.get_specific_fn('return_data_desc', generic_fns.pipes.get_type(), raise_error=False) 300 301 # Loop over the spins. 302 for i in xrange(len(self)): 303 # Create an XML element for this spin and add it to the higher level element. 304 spin_element = doc.createElement('spin') 305 element.appendChild(spin_element) 306 307 # Set the spin attributes. 308 spin_element.setAttribute('desc', 'Spin container') 309 spin_element.setAttribute('name', str(self[i].name)) 310 spin_element.setAttribute('num', str(self[i].num)) 311 312 # Get the spin specific object names and loop over them to get their descriptions. 313 object_info = [] 314 try: 315 for name in data_names(error_names=True, sim_names=True): 316 # Get the description. 317 if return_data_desc: 318 desc = return_data_desc(name) 319 else: 320 desc = None 321 322 # Append the two. 323 object_info.append([name, desc]) 324 except RelaxImplementError: 325 pass 326 327 # Add the ordered objects. 328 blacklist = [] 329 for name, desc in object_info: 330 # Add the name to the blacklist. 331 blacklist.append(name) 332 333 # Skip the object if it is missing from the SpinContainer. 334 if not hasattr(self[i], name): 335 continue 336 337 # Create a new element for this object, and add it to the main element. 338 sub_element = doc.createElement(name) 339 spin_element.appendChild(sub_element) 340 341 # Add the object description. 342 if desc: 343 sub_element.setAttribute('desc', desc) 344 345 # Get the object. 346 object = getattr(self[i], name) 347 348 # Store floats as IEEE-754 byte arrays (for full precision storage). 349 if isinstance(object, float) or isinstance(object, numpy.float64): 350 sub_element.setAttribute('ieee_754_byte_array', repr(floatAsByteArray(object))) 351 352 # Add the text value to the sub element. 353 text_val = doc.createTextNode(repr(object)) 354 sub_element.appendChild(text_val) 355 356 # Add all simple python objects within the SpinContainer to the XML element. 357 fill_object_contents(doc, spin_element, object=self[i], blacklist=['name', 'num', 'spin'] + blacklist + list(self[i].__class__.__dict__.keys()))
358 359 360 361 # The residue data. 362 ################### 363
364 -class ResidueContainer(Prototype):
365 """Class containing all the residue specific data.""" 366
367 - def __init__(self, res_name=None, res_num=None):
368 """Set up the default objects of the residue data container.""" 369 370 # The residue name and number. 371 self.name = res_name 372 self.num = res_num 373 374 # The empty spin system list. 375 self.spin = SpinList()
376 377
378 - def __repr__(self):
379 """The string representation of the object. 380 381 Rather than using the standard Python conventions (either the string representation of the 382 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 383 """ 384 385 # Intro. 386 text = "Class containing all the residue specific data.\n" 387 388 # Objects. 389 text = text + "\n" 390 text = text + "Objects:\n" 391 for name in dir(self): 392 # Spin systems. 393 if name == 'spin': 394 text = text + " spin: The list of spin systems of the residues\n" 395 continue 396 397 # Skip the ResidueContainer methods. 398 if name == 'is_empty': 399 continue 400 401 # Skip special objects. 402 if match("^_", name): 403 continue 404 405 # Add the object's attribute to the text string. 406 text = text + " " + name + ": " + repr(getattr(self, name)) + "\n" 407 408 return text
409 410
411 - def is_empty(self):
412 """Method for testing if this ResidueContainer object is empty. 413 414 @return: True if this container is empty and the residue number and name have not been 415 set, False otherwise. 416 @rtype: bool 417 """ 418 419 # The residue number or residue name have been set. 420 if self.num != None or self.name != None: 421 return False 422 423 # An object has been added to the container. 424 for name in dir(self): 425 # Skip the objects initialised in __init__(). 426 if name == 'num' or name == 'name' or name == 'spin': 427 continue 428 429 # Skip the ResidueContainer methods. 430 if name == 'is_empty': 431 continue 432 433 # Skip special objects. 434 if match("^_", name): 435 continue 436 437 # An object has been added. 438 return False 439 440 # The spin list is not empty. 441 if not self.spin.is_empty(): 442 return False 443 444 # The ResidueContainer is unmodified. 445 return True
446 447
448 -class ResidueList(list):
449 """List type data container for residue specific data.""" 450
451 - def __init__(self):
452 """Set up the first residue data container.""" 453 454 # Add the initial residue container at index 0. 455 self.append(ResidueContainer())
456 457
458 - def __repr__(self):
459 """The string representation of the object. 460 461 Rather than using the standard Python conventions (either the string representation of the 462 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 463 """ 464 465 # Intro. 466 text = "Residues.\n\n" 467 468 # Residue data. 469 text = text + "%-8s%-8s%-8s" % ("Index", "Number", "Name") + "\n" 470 for i in xrange(len(self)): 471 text = text + "%-8i%-8s%-8s" % (i, repr(self[i].num), self[i].name) + "\n" 472 text = text + "\nThese can be accessed by typing 'D.mol[i].res[j]', where D is the relax data storage object.\n" 473 474 return text
475 476
477 - def add_item(self, res_name=None, res_num=None):
478 """Append an empty ResidueContainer to the ResidueList.""" 479 480 # If no residue data exists, replace the empty first residue with this residue. 481 if self.is_empty(): 482 self[0].num = res_num 483 self[0].name = res_name 484 485 # Otherwise append a new ResidueContainer. 486 else: 487 # Test if the residue number (or name if unnumbered) already exists. 488 for i in xrange(len(self)): 489 # Residue number has been supplied. 490 if res_num != None: 491 if self[i].num == res_num: 492 raise RelaxError("The residue number '" + repr(res_num) + "' already exists in the sequence.") 493 494 # No residue numbers. 495 else: 496 if self[i].name == res_name: 497 raise RelaxError("The unnumbered residue name '" + repr(res_name) + "' already exists.") 498 499 # Append a new ResidueContainer. 500 self.append(ResidueContainer(res_name, res_num))
501 502
503 - def is_empty(self):
504 """Method for testing if this ResidueList object is empty. 505 506 @return: True if this list only has one ResidueContainer and the residue number and name 507 have not been set, False otherwise. 508 @rtype: bool 509 """ 510 511 # There is only one ResidueContainer and it is empty. 512 if len(self) == 1 and self[0].is_empty(): 513 return True 514 515 # Otherwise. 516 return False
517 518
519 - def from_xml(self, res_nodes, file_version=None):
520 """Recreate a residue list data structure from the XML residue nodes. 521 522 @param res_nodes: The residue XML nodes. 523 @type res_nodes: xml.dom.minicompat.NodeList instance 524 @keyword file_version: The relax version used to create the XML file. 525 @type file_version: str 526 """ 527 528 # Test if empty. 529 if not self.is_empty(): 530 raise RelaxFromXMLNotEmptyError(self.__class__.__name__) 531 532 # Loop over the residues. 533 for res_node in res_nodes: 534 # Get the residue details and add the residue to the ResidueList structure. 535 name = str(res_node.getAttribute('name')) 536 if name == 'None': 537 name = None 538 num = eval(res_node.getAttribute('num')) 539 self.add_item(res_name=name, res_num=num) 540 541 # Get the spin nodes. 542 spin_nodes = res_node.getElementsByTagName('spin') 543 544 # Recreate the spin data structures for the current residue. 545 self[-1].spin.from_xml(spin_nodes, file_version=file_version)
546 547
548 - def to_xml(self, doc, element):
549 """Create XML elements for each residue. 550 551 @param doc: The XML document object. 552 @type doc: xml.dom.minidom.Document instance 553 @param element: The element to add the residue XML elements to. 554 @type element: XML element object 555 """ 556 557 # Loop over the residues. 558 for i in xrange(len(self)): 559 # Create an XML element for this residue and add it to the higher level element. 560 res_element = doc.createElement('res') 561 element.appendChild(res_element) 562 563 # Set the residue attributes. 564 res_element.setAttribute('desc', 'Residue container') 565 res_element.setAttribute('name', str(self[i].name)) 566 res_element.setAttribute('num', str(self[i].num)) 567 568 # Add all simple python objects within the ResidueContainer to the XML element. 569 fill_object_contents(doc, res_element, object=self[i], blacklist=['name', 'num', 'spin'] + list(self[i].__class__.__dict__.keys())) 570 571 # Add the residue data. 572 self[i].spin.to_xml(doc, res_element)
573 574 575 576 # The molecule data. 577 ################### 578
579 -class MoleculeContainer(Prototype):
580 """Class containing all the molecule specific data.""" 581
582 - def __init__(self, mol_name=None, mol_type=None):
583 """Set up the default objects of the molecule data container.""" 584 585 # The name of the molecule, corresponding to that of the structure file if specified. 586 self.name = mol_name 587 588 # The type of molecule. 589 self.type = mol_type 590 591 # The empty residue list. 592 self.res = ResidueList()
593 594
595 - def __repr__(self):
596 """The string representation of the object. 597 598 Rather than using the standard Python conventions (either the string representation of the 599 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 600 """ 601 602 # Intro. 603 text = "Class containing all the molecule specific data.\n" 604 605 # Objects. 606 text = text + "\n" 607 text = text + "Objects:\n" 608 for name in dir(self): 609 # Residue list. 610 if name == 'res': 611 text = text + " res: The list of the residues of the molecule\n" 612 continue 613 614 # Skip the MoleculeContainer methods. 615 if name == 'is_empty': 616 continue 617 618 # Skip special objects. 619 if match("^_", name): 620 continue 621 622 # Add the object's attribute to the text string. 623 text = text + " " + name + ": " + repr(getattr(self, name)) + "\n" 624 625 return text
626 627
628 - def is_empty(self):
629 """Method for testing if this MoleculeContainer object is empty. 630 631 @return: True if this container is empty and the molecule name has not been set, False 632 otherwise. 633 @rtype: bool 634 """ 635 636 # The molecule name has been set. 637 if self.name != None: 638 return False 639 640 # An object has been added to the container. 641 for name in dir(self): 642 # Skip the objects initialised in __init__(). 643 if name in ['name', 'res', 'type']: 644 continue 645 646 # Skip the MoleculeContainer methods. 647 if name == 'is_empty': 648 continue 649 650 # Skip special objects. 651 if match("^_", name): 652 continue 653 654 # An object has been added. 655 return False 656 657 # The residue list is not empty. 658 if not self.res.is_empty(): 659 return False 660 661 # The MoleculeContainer is unmodified. 662 return True
663 664
665 -class MoleculeList(list):
666 """List type data container for the molecule specific data.""" 667
668 - def __init__(self):
669 """Set up the first molecule data container.""" 670 671 # Add the initial molecule container at index 0. 672 self.append(MoleculeContainer())
673 674
675 - def __repr__(self):
676 """The string representation of the object. 677 678 Rather than using the standard Python conventions (either the string representation of the 679 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 680 """ 681 682 text = "Molecules.\n\n" 683 text = text + "%-8s%-8s" % ("Index", "Name") + "\n" 684 for i in xrange(len(self)): 685 text = text + "%-8i%-8s" % (i, self[i].name) + "\n" 686 text = text + "\nThese can be accessed by typing 'D.mol[i]', where D is the relax data storage object.\n" 687 return text
688 689
690 - def add_item(self, mol_name=None, mol_type=None):
691 """Append an empty MoleculeContainer to the MoleculeList.""" 692 693 # If no molecule data exists, replace the empty first molecule with this molecule (just a renaming). 694 if self.is_empty(): 695 self[0].name = mol_name 696 self[0].type = mol_type 697 698 # Otherwise append an empty MoleculeContainer. 699 else: 700 # Test if the molecule name already exists. 701 for i in xrange(len(self)): 702 if self[i].name == mol_name: 703 raise RelaxError("The molecule '%s' already exists in the sequence." % mol_name) 704 705 # Append an empty MoleculeContainer. 706 self.append(MoleculeContainer(mol_name, mol_type))
707 708
709 - def is_empty(self):
710 """Method for testing if this MoleculeList object is empty. 711 712 @return: True if this list only has one MoleculeContainer and the molecule name has not 713 been set, False otherwise. 714 @rtype: bool 715 """ 716 717 # There is only one MoleculeContainer and it is empty. 718 if len(self) == 1 and self[0].is_empty(): 719 return True 720 721 # Otherwise. 722 return False
723 724
725 - def from_xml(self, mol_nodes, file_version=None):
726 """Recreate a molecule list data structure from the XML molecule nodes. 727 728 @param mol_nodes: The molecule XML nodes. 729 @type mol_nodes: xml.dom.minicompat.NodeList instance 730 @keyword file_version: The relax version used to create the XML file. 731 @type file_version: str 732 """ 733 734 # Test if empty. 735 if not self.is_empty(): 736 raise RelaxFromXMLNotEmptyError(self.__class__.__name__) 737 738 # Loop over the molecules. 739 for mol_node in mol_nodes: 740 # Get the molecule details and add the molecule to the MoleculeList structure. 741 name = mol_node.getAttribute('name') 742 if name == 'None': 743 name = None 744 type = mol_node.getAttribute('type') 745 if type == 'None': 746 type = None 747 self.add_item(mol_name=name, mol_type=type) 748 749 # Get the residue nodes. 750 res_nodes = mol_node.getElementsByTagName('res') 751 752 # Recreate the residue data structures for the current molecule. 753 self[-1].res.from_xml(res_nodes, file_version=file_version)
754 755
756 - def to_xml(self, doc, element):
757 """Create XML elements for each molecule. 758 759 @param doc: The XML document object. 760 @type doc: xml.dom.minidom.Document instance 761 @param element: The element to add the molecule XML elements to. 762 @type element: XML element object 763 """ 764 765 # Loop over the molecules. 766 for i in xrange(len(self)): 767 # Create an XML element for this molecule and add it to the higher level element. 768 mol_element = doc.createElement('mol') 769 element.appendChild(mol_element) 770 771 # Set the molecule attributes. 772 mol_element.setAttribute('desc', 'Molecule container') 773 mol_element.setAttribute('name', str(self[i].name)) 774 mol_element.setAttribute('type', str(self[i].type)) 775 776 # Add all simple python objects within the MoleculeContainer to the XML element. 777 fill_object_contents(doc, mol_element, object=self[i], blacklist=['name', 'res', 'type'] + list(self[i].__class__.__dict__.keys())) 778 779 # Add the residue data. 780 self[i].res.to_xml(doc, mol_element)
781