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

Source Code for Module data_store.mol_res_spin

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2001-2004,2006-2008,2010-2012,2014,2017 Edward d'Auvergne     # 
  4  # Copyright (C) 2006 Chris MacRaild                                           # 
  5  #                                                                             # 
  6  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  7  #                                                                             # 
  8  # This program is free software: you can redistribute it and/or modify        # 
  9  # it under the terms of the GNU General Public License as published by        # 
 10  # the Free Software Foundation, either version 3 of the License, or           # 
 11  # (at your option) any later version.                                         # 
 12  #                                                                             # 
 13  # This program is distributed in the hope that it will be useful,             # 
 14  # but WITHOUT ANY WARRANTY; without even the implied warranty of              # 
 15  # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               # 
 16  # GNU General Public License for more details.                                # 
 17  #                                                                             # 
 18  # You should have received a copy of the GNU General Public License           # 
 19  # along with this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 20  #                                                                             # 
 21  ############################################################################### 
 22   
 23  # Module docstring. 
 24  """The molecule-residue-spin containers of the relax data store.""" 
 25   
 26  # Python module imports. 
 27  from binascii import hexlify 
 28  from os import urandom 
 29  from re import match 
 30   
 31  # relax module imports. 
 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  # The spin system data. 
 39  ####################### 
 40   
41 -class SpinContainer(Prototype):
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 # The spin system name and number. 56 self.name = spin_name 57 self.num = spin_num 58 self.select = select 59 60 # Generate a unique hash for the spin. 61 self._generate_hash() 62 63 # The identifiers for all interatomic interactions (InteratomContainer hashes). 64 self._interatomic_hashes = [] 65 66 # The private metadata. 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
76 - def __repr__(self):
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 # Intro. 84 text = "Class containing all the spin system specific data.\n\n" 85 86 # Objects. 87 text = text + "\n" 88 text = text + "Objects:\n" 89 for name in dir(self): 90 # Skip the SpinContainer methods. 91 if name == 'is_empty': 92 continue 93 94 # Skip special objects. 95 if name not in ['_spin_ids', '_hash'] and match("^_", name): 96 continue 97 98 # Add the object's attribute to the text string. 99 text = text + " " + name + ": " + repr(getattr(self, name)) + "\n" 100 101 return text
102 103
104 - def _back_compat_hook(self, file_version=None):
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 # Model-free parameters. 112 if hasattr(self, 'equation') and self.equation in ['mf_orig', 'mf_ext', 'mf_ext2']: 113 self._back_compat_hook_mf_data() 114 115 # Relaxation data. 116 self._back_compat_hook_ri_data()
117 118
120 """Converting the old model-free parameter vector to the new one.""" 121 122 # Nothing to do. 123 if not hasattr(self, 'params'): 124 return 125 126 # Loop over the parameters, converting them to lowercase. 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 # Nothing to do. 135 if not (hasattr(self, 'frq_labels') and hasattr(self, 'noe_r1_table') and hasattr(self, 'remap_table')): 136 return 137 138 # Initialise the new structures. 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 # Generate the new structures. 147 for i in range(self.num_ri): 148 # The ID. 149 ri_id = "%s_%s" % (self.ri_labels[i], self.frq_labels[self.remap_table[i]]) 150 151 # The relaxation data. 152 self.ri_data[ri_id] = self.relax_data[i] 153 self.ri_data_err[ri_id] = self.relax_error[i] 154 155 # Simulation data. 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 # Delete the old structures. 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
175 - def _generate_hash(self):
176 """Generate a unique hash for the spin.""" 177 178 # The hash. 179 self._hash = hexlify(urandom(20))
180 181
182 - def is_empty(self):
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 # The spin number or spin name has been set. 191 if self.num != None or self.name != None: 192 return False 193 194 # An object has been added to the container. 195 for name in dir(self): 196 # Skip the objects initialised in __init__(). 197 if name == 'num' or name == 'name' or name == 'select': 198 continue 199 200 # Skip the SpinContainer methods. 201 if name == 'is_empty': 202 continue 203 204 # Skip special objects. 205 if match("^_", name): 206 continue 207 208 # An object has been added. 209 return False 210 211 # The SpinContainer is unmodified. 212 return True
213 214
215 -class SpinList(list):
216 """List type data container for spin system specific data.""" 217
218 - def __init__(self):
219 """Set up the first spin system data container.""" 220 221 # Add the initial spin system container at index 0. 222 self.append(SpinContainer())
223 224
225 - def __repr__(self):
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 # Intro. 233 text = "Spin systems.\n\n" 234 235 # Residue data. 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 # If no spin data exists, replace the empty first spin with this spin. 258 if self.is_empty(): 259 self[0].num = spin_num 260 self[0].name = spin_name 261 self[0].select = select 262 263 # Return the container. 264 return self[0] 265 266 # Otherwise append a new SpinContainer. 267 else: 268 # Test if the spin number (or name if unnumbered) already exists. 269 for i in range(len(self)): 270 # Spin number has been supplied. 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 # No spin numbers. 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 # Append a new SpinContainer. 280 self.append(SpinContainer(spin_name, spin_num, select)) 281 282 # Return the container. 283 return self[-1]
284 285
286 - def is_empty(self):
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 # There is only one SpinContainer and it is empty. 295 if len(self) == 1 and self[0].is_empty(): 296 return True 297 298 # Otherwise. 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 # Test if empty. 312 if not self.is_empty(): 313 raise RelaxFromXMLNotEmptyError(self.__class__.__name__) 314 315 # Loop over the spins. 316 for spin_node in spin_nodes: 317 # Get the spin details and add the spin to the SpinList structure. 318 name = str(spin_node.getAttribute('name')) 319 if name == 'None': 320 name = None 321 num = eval(spin_node.getAttribute('num')) 322 323 # Get the spin details and add the spin to the SpinList structure. 324 self.add_item(spin_name=name, spin_num=num) 325 326 # Recreate the current spin container. 327 xml_to_object(spin_node, self[-1], file_version=file_version) 328 329 # Backwards compatibility transformations. 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 # The specific analysis API object. 345 api = specific_analyses.api.return_api(analysis_type=pipe_type) 346 347 # Loop over the spins. 348 for i in range(len(self)): 349 # Create an XML element for this spin and add it to the higher level element. 350 spin_element = doc.createElement('spin') 351 element.appendChild(spin_element) 352 353 # Set the spin attributes. 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 # Get the spin specific object names and loop over them to get their descriptions. 359 object_info = [] 360 try: 361 for name in api.data_names(error_names=True, sim_names=True): 362 # Get the description. 363 if hasattr(api, 'return_data_desc'): 364 desc = api.return_data_desc(name) 365 else: 366 desc = None 367 368 # Append the two. 369 object_info.append([name, desc]) 370 except RelaxImplementError: 371 pass 372 373 # Add the ordered objects. 374 blacklist = [] 375 for name, desc in object_info: 376 # Add the name to the blacklist. 377 blacklist.append(name) 378 379 # Skip the object if it is missing from the SpinContainer. 380 if not hasattr(self[i], name): 381 continue 382 383 # Create a new element for this object, and add it to the main element. 384 sub_element = doc.createElement(name) 385 spin_element.appendChild(sub_element) 386 387 # Add the object description. 388 if desc: 389 sub_element.setAttribute('desc', desc) 390 391 # Get the object. 392 object = getattr(self[i], name) 393 394 # Convert to XML. 395 object_to_xml(doc, sub_element, value=object) 396 397 # Add all simple python objects within the SpinContainer to the XML element. 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 # The residue data. 403 ################### 404
405 -class ResidueContainer(Prototype):
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 # The residue name and number. 412 self.name = res_name 413 self.num = res_num 414 415 # The private metadata. 416 self._mol_name = None 417 self._mol_index = None 418 self._res_index = None 419 420 # The empty spin system list. 421 self.spin = SpinList()
422 423
424 - def __repr__(self):
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 # Intro. 432 text = "Class containing all the residue specific data.\n" 433 434 # Objects. 435 text = text + "\n" 436 text = text + "Objects:\n" 437 for name in dir(self): 438 # Spin systems. 439 if name == 'spin': 440 text = text + " spin: The list of spin systems of the residues\n" 441 continue 442 443 # Skip the ResidueContainer methods. 444 if name == 'is_empty': 445 continue 446 447 # Skip special objects. 448 if match("^_", name): 449 continue 450 451 # Add the object's attribute to the text string. 452 text = text + " " + name + ": " + repr(getattr(self, name)) + "\n" 453 454 return text
455 456
457 - def is_empty(self):
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 # The residue number or residue name have been set. 466 if self.num != None or self.name != None: 467 return False 468 469 # An object has been added to the container. 470 for name in dir(self): 471 # Skip the objects initialised in __init__(). 472 if name == 'num' or name == 'name' or name == 'spin': 473 continue 474 475 # Skip the ResidueContainer methods. 476 if name == 'is_empty': 477 continue 478 479 # Skip special objects. 480 if match("^_", name): 481 continue 482 483 # An object has been added. 484 return False 485 486 # The spin list is not empty. 487 if not self.spin.is_empty(): 488 return False 489 490 # The ResidueContainer is unmodified. 491 return True
492 493
494 -class ResidueList(list):
495 """List type data container for residue specific data.""" 496
497 - def __init__(self):
498 """Set up the first residue data container.""" 499 500 # Add the initial residue container at index 0. 501 self.append(ResidueContainer())
502 503
504 - def __repr__(self):
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 # Intro. 512 text = "Residues.\n\n" 513 514 # Residue data. 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 # If no residue data exists, replace the empty first residue with this residue. 527 if self.is_empty(): 528 self[0].num = res_num 529 self[0].name = res_name 530 531 # Otherwise append a new ResidueContainer. 532 else: 533 # Test if the residue number (or name if unnumbered) already exists. 534 for i in range(len(self)): 535 # Residue number has been supplied. 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 # No residue numbers. 541 else: 542 if self[i].name == res_name: 543 raise RelaxError("The unnumbered residue name '" + repr(res_name) + "' already exists.") 544 545 # Append a new ResidueContainer. 546 self.append(ResidueContainer(res_name, res_num))
547 548
549 - def is_empty(self):
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 # There is only one ResidueContainer and it is empty. 558 if len(self) == 1 and self[0].is_empty(): 559 return True 560 561 # Otherwise. 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 # Test if empty. 575 if not self.is_empty(): 576 raise RelaxFromXMLNotEmptyError(self.__class__.__name__) 577 578 # Loop over the residues. 579 for res_node in res_nodes: 580 # Get the residue details and add the residue to the ResidueList structure. 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 # Get the spin nodes. 588 spin_nodes = res_node.getElementsByTagName('spin') 589 590 # Recreate the spin data structures for the current residue. 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 # Loop over the residues. 606 for i in range(len(self)): 607 # Create an XML element for this residue and add it to the higher level element. 608 res_element = doc.createElement('res') 609 element.appendChild(res_element) 610 611 # Set the residue attributes. 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 # Add all simple python objects within the ResidueContainer to the XML element. 617 fill_object_contents(doc, res_element, object=self[i], blacklist=['name', 'num', 'spin'] + list(self[i].__class__.__dict__.keys())) 618 619 # Add the residue data. 620 self[i].spin.to_xml(doc, res_element, pipe_type=pipe_type)
621 622 623 624 # The molecule data. 625 ################### 626
627 -class MoleculeContainer(Prototype):
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 # The name of the molecule, corresponding to that of the structure file if specified. 634 self.name = mol_name 635 636 # The type of molecule. 637 self.type = mol_type 638 639 # The private metadata. 640 self._mol_index = None 641 642 # The empty residue list. 643 self.res = ResidueList()
644 645
646 - def __repr__(self):
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 # Intro. 654 text = "Class containing all the molecule specific data.\n" 655 656 # Objects. 657 text = text + "\n" 658 text = text + "Objects:\n" 659 for name in dir(self): 660 # Residue list. 661 if name == 'res': 662 text = text + " res: The list of the residues of the molecule\n" 663 continue 664 665 # Skip the MoleculeContainer methods. 666 if name == 'is_empty': 667 continue 668 669 # Skip special objects. 670 if match("^_", name): 671 continue 672 673 # Add the object's attribute to the text string. 674 text = text + " " + name + ": " + repr(getattr(self, name)) + "\n" 675 676 return text
677 678
679 - def is_empty(self):
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 # The molecule name has been set. 688 if self.name != None: 689 return False 690 691 # An object has been added to the container. 692 for name in dir(self): 693 # Skip the objects initialised in __init__(). 694 if name in ['name', 'res', 'type']: 695 continue 696 697 # Skip the MoleculeContainer methods. 698 if name == 'is_empty': 699 continue 700 701 # Skip special objects. 702 if match("^_", name): 703 continue 704 705 # An object has been added. 706 return False 707 708 # The residue list is not empty. 709 if not self.res.is_empty(): 710 return False 711 712 # The MoleculeContainer is unmodified. 713 return True
714 715
716 -class MoleculeList(list):
717 """List type data container for the molecule specific data.""" 718
719 - def __init__(self):
720 """Set up the first molecule data container.""" 721 722 # Add the initial molecule container at index 0. 723 self.append(MoleculeContainer()) 724 725 # Create special private lookup tables for fast spin accesses. 726 self._spin_id_lookup = {} 727 self._spin_hash_lookup = {}
728 729
730 - def __repr__(self):
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 # If no molecule data exists, replace the empty first molecule with this molecule (just a renaming). 749 if self.is_empty(): 750 self[0].name = mol_name 751 self[0].type = mol_type 752 753 # Otherwise append an empty MoleculeContainer. 754 else: 755 # Test if the molecule name already exists. 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 # Append an empty MoleculeContainer. 761 self.append(MoleculeContainer(mol_name, mol_type))
762 763
764 - def is_empty(self):
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 # There is only one MoleculeContainer and it is empty. 773 if len(self) == 1 and self[0].is_empty(): 774 return True 775 776 # Otherwise. 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 # Test if empty. 790 if not self.is_empty(): 791 raise RelaxFromXMLNotEmptyError(self.__class__.__name__) 792 793 # Loop over the molecules. 794 for mol_node in mol_nodes: 795 # Get the molecule details and add the molecule to the MoleculeList structure. 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 # Get the residue nodes. 805 res_nodes = mol_node.getElementsByTagName('res') 806 807 # Recreate the residue data structures for the current molecule. 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 # Loop over the molecules. 823 for i in range(len(self)): 824 # Create an XML element for this molecule and add it to the higher level element. 825 mol_element = doc.createElement('mol') 826 element.appendChild(mol_element) 827 828 # Set the molecule attributes. 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 # Add all simple python objects within the MoleculeContainer to the XML element. 834 fill_object_contents(doc, mol_element, object=self[i], blacklist=['name', 'res', 'type'] + list(self[i].__class__.__dict__.keys())) 835 836 # Add the residue data. 837 self[i].res.to_xml(doc, mol_element, pipe_type=pipe_type)
838