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, object_to_xml, 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 XML version of the XML file. 87 @type file_version: int 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 # Delete the old structures. 140 del self.frq 141 del self.frq_labels 142 del self.noe_r1_table 143 del self.num_frq 144 del self.num_ri 145 del self.ri_labels 146 del self.remap_table 147 del self.relax_data 148 del self.relax_error 149 if sims: 150 del self.relax_sim_data
151 152
153 - def is_empty(self):
154 """Method for testing if this SpinContainer object is empty. 155 156 @return: True if this container is empty and the spin number and name have not been set, 157 False otherwise. 158 @rtype: bool 159 """ 160 161 # The spin number or spin name has been set. 162 if self.num != None or self.name != None: 163 return False 164 165 # An object has been added to the container. 166 for name in dir(self): 167 # Skip the objects initialised in __init__(). 168 if name == 'num' or name == 'name' or name == 'select': 169 continue 170 171 # Skip the SpinContainer methods. 172 if name == 'is_empty': 173 continue 174 175 # Skip special objects. 176 if match("^_", name): 177 continue 178 179 # An object has been added. 180 return False 181 182 # The SpinContainer is unmodified. 183 return True
184 185
186 -class SpinList(list):
187 """List type data container for spin system specific data.""" 188
189 - def __init__(self):
190 """Set up the first spin system data container.""" 191 192 # Add the initial spin system container at index 0. 193 self.append(SpinContainer())
194 195
196 - def __repr__(self):
197 """The string representation of the object. 198 199 Rather than using the standard Python conventions (either the string representation of the 200 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 201 """ 202 203 # Intro. 204 text = "Spin systems.\n\n" 205 206 # Residue data. 207 text = text + "%-8s%-8s%-8s%-10s" % ("Index", "Number", "Name", "Selected") + "\n" 208 for i in xrange(len(self)): 209 text = text + "%-8i%-8s%-8s%-10s" % (i, repr(self[i].num), self[i].name, self[i].select) + "\n" 210 text = text + "\nThese can be accessed by typing 'D.mol[i].res[j].spin[k]', where D is the relax data storage object.\n" 211 212 return text
213 214
215 - def add_item(self, spin_name=None, spin_num=None, select=True):
216 """Function for appending an empty container to the list.""" 217 218 # If no spin data exists, replace the empty first spin with this spin. 219 if self.is_empty(): 220 self[0].num = spin_num 221 self[0].name = spin_name 222 self[0].select = select 223 224 # Otherwise append a new SpinContainer. 225 else: 226 # Test if the spin number (or name if unnumbered) already exists. 227 for i in xrange(len(self)): 228 # Spin number has been supplied. 229 if spin_num != None: 230 if self[i].num == spin_num: 231 raise RelaxError("The spin number '" + repr(spin_num) + "' already exists.") 232 233 # No spin numbers. 234 else: 235 if self[i].name == spin_name: 236 raise RelaxError("The unnumbered spin name '" + repr(spin_name) + "' already exists.") 237 238 # Append a new SpinContainer. 239 self.append(SpinContainer(spin_name, spin_num, select))
240 241
242 - def is_empty(self):
243 """Method for testing if this SpinList object is empty. 244 245 @return: True if this list only has one SpinContainer and the spin number and name have 246 not been set, False otherwise. 247 @rtype: bool 248 """ 249 250 # There is only one SpinContainer and it is empty. 251 if len(self) == 1 and self[0].is_empty(): 252 return True 253 254 # Otherwise. 255 return False
256 257
258 - def from_xml(self, spin_nodes, file_version=None):
259 """Recreate a spin list data structure from the XML spin nodes. 260 261 @param spin_nodes: The spin XML nodes. 262 @type spin_nodes: xml.dom.minicompat.NodeList instance 263 @keyword file_version: The relax XML version of the XML file. 264 @type file_version: int 265 """ 266 267 # Test if empty. 268 if not self.is_empty(): 269 raise RelaxFromXMLNotEmptyError(self.__class__.__name__) 270 271 # Loop over the spins. 272 for spin_node in spin_nodes: 273 # Get the spin details and add the spin to the SpinList structure. 274 name = str(spin_node.getAttribute('name')) 275 if name == 'None': 276 name = None 277 num = eval(spin_node.getAttribute('num')) 278 self.add_item(spin_name=name, spin_num=num) 279 280 # Recreate the current spin container. 281 xml_to_object(spin_node, self[-1], file_version=file_version) 282 283 # Backwards compatibility transformations. 284 self[-1]._back_compat_hook(file_version)
285 286
287 - def to_xml(self, doc, element):
288 """Create XML elements for each spin. 289 290 @param doc: The XML document object. 291 @type doc: xml.dom.minidom.Document instance 292 @param element: The element to add the spin XML elements to. 293 @type element: XML element object 294 """ 295 296 # Get the specific functions. 297 data_names = specific_fns.setup.get_specific_fn('data_names', generic_fns.pipes.get_type(), raise_error=False) 298 return_data_desc = specific_fns.setup.get_specific_fn('return_data_desc', generic_fns.pipes.get_type(), raise_error=False) 299 300 # Loop over the spins. 301 for i in xrange(len(self)): 302 # Create an XML element for this spin and add it to the higher level element. 303 spin_element = doc.createElement('spin') 304 element.appendChild(spin_element) 305 306 # Set the spin attributes. 307 spin_element.setAttribute('desc', 'Spin container') 308 spin_element.setAttribute('name', str(self[i].name)) 309 spin_element.setAttribute('num', str(self[i].num)) 310 311 # Get the spin specific object names and loop over them to get their descriptions. 312 object_info = [] 313 try: 314 for name in data_names(error_names=True, sim_names=True): 315 # Get the description. 316 if return_data_desc: 317 desc = return_data_desc(name) 318 else: 319 desc = None 320 321 # Append the two. 322 object_info.append([name, desc]) 323 except RelaxImplementError: 324 pass 325 326 # Add the ordered objects. 327 blacklist = [] 328 for name, desc in object_info: 329 # Add the name to the blacklist. 330 blacklist.append(name) 331 332 # Skip the object if it is missing from the SpinContainer. 333 if not hasattr(self[i], name): 334 continue 335 336 # Create a new element for this object, and add it to the main element. 337 sub_element = doc.createElement(name) 338 spin_element.appendChild(sub_element) 339 340 # Add the object description. 341 if desc: 342 sub_element.setAttribute('desc', desc) 343 344 # Get the object. 345 object = getattr(self[i], name) 346 347 # Convert to XML. 348 object_to_xml(doc, sub_element, value=object) 349 350 # Add all simple python objects within the SpinContainer to the XML element. 351 fill_object_contents(doc, spin_element, object=self[i], blacklist=['name', 'num', 'spin'] + blacklist + list(self[i].__class__.__dict__.keys()))
352 353 354 355 # The residue data. 356 ################### 357
358 -class ResidueContainer(Prototype):
359 """Class containing all the residue specific data.""" 360
361 - def __init__(self, res_name=None, res_num=None):
362 """Set up the default objects of the residue data container.""" 363 364 # The residue name and number. 365 self.name = res_name 366 self.num = res_num 367 368 # The empty spin system list. 369 self.spin = SpinList()
370 371
372 - def __repr__(self):
373 """The string representation of the object. 374 375 Rather than using the standard Python conventions (either the string representation of the 376 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 377 """ 378 379 # Intro. 380 text = "Class containing all the residue specific data.\n" 381 382 # Objects. 383 text = text + "\n" 384 text = text + "Objects:\n" 385 for name in dir(self): 386 # Spin systems. 387 if name == 'spin': 388 text = text + " spin: The list of spin systems of the residues\n" 389 continue 390 391 # Skip the ResidueContainer methods. 392 if name == 'is_empty': 393 continue 394 395 # Skip special objects. 396 if match("^_", name): 397 continue 398 399 # Add the object's attribute to the text string. 400 text = text + " " + name + ": " + repr(getattr(self, name)) + "\n" 401 402 return text
403 404
405 - def is_empty(self):
406 """Method for testing if this ResidueContainer object is empty. 407 408 @return: True if this container is empty and the residue number and name have not been 409 set, False otherwise. 410 @rtype: bool 411 """ 412 413 # The residue number or residue name have been set. 414 if self.num != None or self.name != None: 415 return False 416 417 # An object has been added to the container. 418 for name in dir(self): 419 # Skip the objects initialised in __init__(). 420 if name == 'num' or name == 'name' or name == 'spin': 421 continue 422 423 # Skip the ResidueContainer methods. 424 if name == 'is_empty': 425 continue 426 427 # Skip special objects. 428 if match("^_", name): 429 continue 430 431 # An object has been added. 432 return False 433 434 # The spin list is not empty. 435 if not self.spin.is_empty(): 436 return False 437 438 # The ResidueContainer is unmodified. 439 return True
440 441
442 -class ResidueList(list):
443 """List type data container for residue specific data.""" 444
445 - def __init__(self):
446 """Set up the first residue data container.""" 447 448 # Add the initial residue container at index 0. 449 self.append(ResidueContainer())
450 451
452 - def __repr__(self):
453 """The string representation of the object. 454 455 Rather than using the standard Python conventions (either the string representation of the 456 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 457 """ 458 459 # Intro. 460 text = "Residues.\n\n" 461 462 # Residue data. 463 text = text + "%-8s%-8s%-8s" % ("Index", "Number", "Name") + "\n" 464 for i in xrange(len(self)): 465 text = text + "%-8i%-8s%-8s" % (i, repr(self[i].num), self[i].name) + "\n" 466 text = text + "\nThese can be accessed by typing 'D.mol[i].res[j]', where D is the relax data storage object.\n" 467 468 return text
469 470
471 - def add_item(self, res_name=None, res_num=None):
472 """Append an empty ResidueContainer to the ResidueList.""" 473 474 # If no residue data exists, replace the empty first residue with this residue. 475 if self.is_empty(): 476 self[0].num = res_num 477 self[0].name = res_name 478 479 # Otherwise append a new ResidueContainer. 480 else: 481 # Test if the residue number (or name if unnumbered) already exists. 482 for i in xrange(len(self)): 483 # Residue number has been supplied. 484 if res_num != None: 485 if self[i].num == res_num: 486 raise RelaxError("The residue number '" + repr(res_num) + "' already exists in the sequence.") 487 488 # No residue numbers. 489 else: 490 if self[i].name == res_name: 491 raise RelaxError("The unnumbered residue name '" + repr(res_name) + "' already exists.") 492 493 # Append a new ResidueContainer. 494 self.append(ResidueContainer(res_name, res_num))
495 496
497 - def is_empty(self):
498 """Method for testing if this ResidueList object is empty. 499 500 @return: True if this list only has one ResidueContainer and the residue number and name 501 have not been set, False otherwise. 502 @rtype: bool 503 """ 504 505 # There is only one ResidueContainer and it is empty. 506 if len(self) == 1 and self[0].is_empty(): 507 return True 508 509 # Otherwise. 510 return False
511 512
513 - def from_xml(self, res_nodes, file_version=None):
514 """Recreate a residue list data structure from the XML residue nodes. 515 516 @param res_nodes: The residue XML nodes. 517 @type res_nodes: xml.dom.minicompat.NodeList instance 518 @keyword file_version: The relax XML version of the XML file. 519 @type file_version: int 520 """ 521 522 # Test if empty. 523 if not self.is_empty(): 524 raise RelaxFromXMLNotEmptyError(self.__class__.__name__) 525 526 # Loop over the residues. 527 for res_node in res_nodes: 528 # Get the residue details and add the residue to the ResidueList structure. 529 name = str(res_node.getAttribute('name')) 530 if name == 'None': 531 name = None 532 num = eval(res_node.getAttribute('num')) 533 self.add_item(res_name=name, res_num=num) 534 535 # Get the spin nodes. 536 spin_nodes = res_node.getElementsByTagName('spin') 537 538 # Recreate the spin data structures for the current residue. 539 self[-1].spin.from_xml(spin_nodes, file_version=file_version)
540 541
542 - def to_xml(self, doc, element):
543 """Create XML elements for each residue. 544 545 @param doc: The XML document object. 546 @type doc: xml.dom.minidom.Document instance 547 @param element: The element to add the residue XML elements to. 548 @type element: XML element object 549 """ 550 551 # Loop over the residues. 552 for i in xrange(len(self)): 553 # Create an XML element for this residue and add it to the higher level element. 554 res_element = doc.createElement('res') 555 element.appendChild(res_element) 556 557 # Set the residue attributes. 558 res_element.setAttribute('desc', 'Residue container') 559 res_element.setAttribute('name', str(self[i].name)) 560 res_element.setAttribute('num', str(self[i].num)) 561 562 # Add all simple python objects within the ResidueContainer to the XML element. 563 fill_object_contents(doc, res_element, object=self[i], blacklist=['name', 'num', 'spin'] + list(self[i].__class__.__dict__.keys())) 564 565 # Add the residue data. 566 self[i].spin.to_xml(doc, res_element)
567 568 569 570 # The molecule data. 571 ################### 572
573 -class MoleculeContainer(Prototype):
574 """Class containing all the molecule specific data.""" 575
576 - def __init__(self, mol_name=None, mol_type=None):
577 """Set up the default objects of the molecule data container.""" 578 579 # The name of the molecule, corresponding to that of the structure file if specified. 580 self.name = mol_name 581 582 # The type of molecule. 583 self.type = mol_type 584 585 # The empty residue list. 586 self.res = ResidueList()
587 588
589 - def __repr__(self):
590 """The string representation of the object. 591 592 Rather than using the standard Python conventions (either the string representation of the 593 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 594 """ 595 596 # Intro. 597 text = "Class containing all the molecule specific data.\n" 598 599 # Objects. 600 text = text + "\n" 601 text = text + "Objects:\n" 602 for name in dir(self): 603 # Residue list. 604 if name == 'res': 605 text = text + " res: The list of the residues of the molecule\n" 606 continue 607 608 # Skip the MoleculeContainer methods. 609 if name == 'is_empty': 610 continue 611 612 # Skip special objects. 613 if match("^_", name): 614 continue 615 616 # Add the object's attribute to the text string. 617 text = text + " " + name + ": " + repr(getattr(self, name)) + "\n" 618 619 return text
620 621
622 - def is_empty(self):
623 """Method for testing if this MoleculeContainer object is empty. 624 625 @return: True if this container is empty and the molecule name has not been set, False 626 otherwise. 627 @rtype: bool 628 """ 629 630 # The molecule name has been set. 631 if self.name != None: 632 return False 633 634 # An object has been added to the container. 635 for name in dir(self): 636 # Skip the objects initialised in __init__(). 637 if name in ['name', 'res', 'type']: 638 continue 639 640 # Skip the MoleculeContainer methods. 641 if name == 'is_empty': 642 continue 643 644 # Skip special objects. 645 if match("^_", name): 646 continue 647 648 # An object has been added. 649 return False 650 651 # The residue list is not empty. 652 if not self.res.is_empty(): 653 return False 654 655 # The MoleculeContainer is unmodified. 656 return True
657 658
659 -class MoleculeList(list):
660 """List type data container for the molecule specific data.""" 661
662 - def __init__(self):
663 """Set up the first molecule data container.""" 664 665 # Add the initial molecule container at index 0. 666 self.append(MoleculeContainer())
667 668
669 - def __repr__(self):
670 """The string representation of the object. 671 672 Rather than using the standard Python conventions (either the string representation of the 673 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 674 """ 675 676 text = "Molecules.\n\n" 677 text = text + "%-8s%-8s" % ("Index", "Name") + "\n" 678 for i in xrange(len(self)): 679 text = text + "%-8i%-8s" % (i, self[i].name) + "\n" 680 text = text + "\nThese can be accessed by typing 'D.mol[i]', where D is the relax data storage object.\n" 681 return text
682 683
684 - def add_item(self, mol_name=None, mol_type=None):
685 """Append an empty MoleculeContainer to the MoleculeList.""" 686 687 # If no molecule data exists, replace the empty first molecule with this molecule (just a renaming). 688 if self.is_empty(): 689 self[0].name = mol_name 690 self[0].type = mol_type 691 692 # Otherwise append an empty MoleculeContainer. 693 else: 694 # Test if the molecule name already exists. 695 for i in xrange(len(self)): 696 if self[i].name == mol_name: 697 raise RelaxError("The molecule '%s' already exists in the sequence." % mol_name) 698 699 # Append an empty MoleculeContainer. 700 self.append(MoleculeContainer(mol_name, mol_type))
701 702
703 - def is_empty(self):
704 """Method for testing if this MoleculeList object is empty. 705 706 @return: True if this list only has one MoleculeContainer and the molecule name has not 707 been set, False otherwise. 708 @rtype: bool 709 """ 710 711 # There is only one MoleculeContainer and it is empty. 712 if len(self) == 1 and self[0].is_empty(): 713 return True 714 715 # Otherwise. 716 return False
717 718
719 - def from_xml(self, mol_nodes, file_version=None):
720 """Recreate a molecule list data structure from the XML molecule nodes. 721 722 @param mol_nodes: The molecule XML nodes. 723 @type mol_nodes: xml.dom.minicompat.NodeList instance 724 @keyword file_version: The relax XML version of the XML file. 725 @type file_version: int 726 """ 727 728 # Test if empty. 729 if not self.is_empty(): 730 raise RelaxFromXMLNotEmptyError(self.__class__.__name__) 731 732 # Loop over the molecules. 733 for mol_node in mol_nodes: 734 # Get the molecule details and add the molecule to the MoleculeList structure. 735 name = str(mol_node.getAttribute('name')) 736 if name == 'None': 737 name = None 738 type = str(mol_node.getAttribute('type')) 739 if type == 'None': 740 type = None 741 self.add_item(mol_name=name, mol_type=type) 742 743 # Get the residue nodes. 744 res_nodes = mol_node.getElementsByTagName('res') 745 746 # Recreate the residue data structures for the current molecule. 747 self[-1].res.from_xml(res_nodes, file_version=file_version)
748 749
750 - def to_xml(self, doc, element):
751 """Create XML elements for each molecule. 752 753 @param doc: The XML document object. 754 @type doc: xml.dom.minidom.Document instance 755 @param element: The element to add the molecule XML elements to. 756 @type element: XML element object 757 """ 758 759 # Loop over the molecules. 760 for i in xrange(len(self)): 761 # Create an XML element for this molecule and add it to the higher level element. 762 mol_element = doc.createElement('mol') 763 element.appendChild(mol_element) 764 765 # Set the molecule attributes. 766 mol_element.setAttribute('desc', 'Molecule container') 767 mol_element.setAttribute('name', str(self[i].name)) 768 mol_element.setAttribute('type', str(self[i].type)) 769 770 # Add all simple python objects within the MoleculeContainer to the XML element. 771 fill_object_contents(doc, mol_element, object=self[i], blacklist=['name', 'res', 'type'] + list(self[i].__class__.__dict__.keys())) 772 773 # Add the residue data. 774 self[i].res.to_xml(doc, mol_element)
775