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

Source Code for Module data.pipe_container

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2007-2013 Edward d'Auvergne                                   # 
  4  #                                                                             # 
  5  # This file is part of the program relax (http://www.nmr-relax.com).          # 
  6  #                                                                             # 
  7  # This program 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 3 of the License, or           # 
 10  # (at your option) any later version.                                         # 
 11  #                                                                             # 
 12  # This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.       # 
 19  #                                                                             # 
 20  ############################################################################### 
 21   
 22  # Module docstring. 
 23  """The data pipe objects of the relax data store.""" 
 24   
 25  # Python module imports. 
 26  from re import match 
 27  from warnings import warn 
 28   
 29  # relax module imports. 
 30  from data.align_tensor import AlignTensorList 
 31  from data.diff_tensor import DiffTensorData 
 32  from data.exp_info import ExpInfo 
 33  from data.interatomic import InteratomList 
 34  from data.mol_res_spin import MoleculeList 
 35  from data.prototype import Prototype 
 36  from data.relax_xml import fill_object_contents, node_value_to_python, xml_to_object 
 37  import generic_fns 
 38  from relax_errors import RelaxFromXMLNotEmptyError 
 39  from relax_warnings import RelaxWarning 
 40   
 41   
42 -class PipeContainer(Prototype):
43 """Class containing all the program data.""" 44
45 - def __init__(self):
46 """Set up all the PipeContainer data structures.""" 47 48 # The molecule-residue-spin object. 49 self.mol = MoleculeList() 50 51 # The interatomic data object. 52 self.interatomic = InteratomList() 53 54 # The data pipe type. 55 self.pipe_type = None 56 57 # Hybrid models. 58 self.hybrid_pipes = []
59 60
61 - def __repr__(self):
62 """The string representation of the object. 63 64 Rather than using the standard Python conventions (either the string representation of the 65 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 66 """ 67 68 # Intro text. 69 text = "The data pipe storage object.\n" 70 71 # Special objects/methods (to avoid the getattr() function call on). 72 spec_obj = ['exp_info', 'mol', 'interatomic', 'diff_tensor', 'structure'] 73 74 # Objects. 75 text = text + "\n" 76 text = text + "Objects:\n" 77 for name in dir(self): 78 # Molecular list. 79 if name == 'mol': 80 text = text + " mol: The molecule list (for the storage of the spin system specific data)\n" 81 82 # Interatomic data list. 83 if name == 'interatomic': 84 text = text + " interatomic: The interatomic data list (for the storage of the inter-spin system data)\n" 85 86 # Diffusion tensor. 87 if name == 'diff_tensor': 88 text = text + " diff_tensor: The Brownian rotational diffusion tensor data object\n" 89 90 # Molecular structure. 91 if name == 'structure': 92 text = text + " structure: The 3D molecular data object\n" 93 94 # The experimental info data container. 95 if name == 'exp_info': 96 text = text + " exp_info: The data container for experimental information\n" 97 98 # Skip the PipeContainer methods. 99 if name in list(self.__class__.__dict__.keys()): 100 continue 101 102 # Skip certain objects. 103 if match("^_", name) or name in spec_obj: 104 continue 105 106 # Add the object's attribute to the text string. 107 text = text + " " + name + ": " + repr(getattr(self, name)) + "\n" 108 109 # Return the text representation. 110 return text
111 112
113 - def _back_compat_hook(self, file_version=None):
114 """Method for converting old data structures to the new ones. 115 116 @keyword file_version: The relax XML version of the XML file. 117 @type file_version: int 118 """ 119 120 # Relaxation data. 121 self._back_compat_hook_ri_data()
122 123
125 """Converting the old relaxation data structures to the new ones.""" 126 127 # Nothing to do. 128 if not (hasattr(cdp, 'frq_labels') and hasattr(cdp, 'noe_r1_table') and hasattr(cdp, 'remap_table')): 129 return 130 131 # Initialise the new structures. 132 cdp.ri_ids = [] 133 cdp.ri_type = {} 134 frq = {} # This will be placed into cdp later as cdp.frq still exists. 135 136 # Generate the new structures. 137 for i in range(cdp.num_ri): 138 # The ID. 139 ri_id = "%s_%s" % (cdp.ri_labels[i], cdp.frq_labels[cdp.remap_table[i]]) 140 141 # Not unique. 142 if ri_id in cdp.ri_ids: 143 # Loop until a unique ID is found. 144 for j in range(100): 145 # New id. 146 new_id = "%s_%s" % (ri_id, j) 147 148 # Unique. 149 if not new_id in cdp.ri_ids: 150 ri_id = new_id 151 break 152 153 # Add the ID. 154 cdp.ri_ids.append(ri_id) 155 156 # The relaxation data type. 157 cdp.ri_type[ri_id] = cdp.ri_labels[i] 158 159 # The frequency data. 160 frq[ri_id] = cdp.frq[cdp.remap_table[i]] 161 162 # Delete the old structures. 163 del cdp.frq 164 del cdp.frq_labels 165 del cdp.noe_r1_table 166 del cdp.num_frq 167 del cdp.num_ri 168 del cdp.remap_table 169 del cdp.ri_labels 170 171 # Set the frequencies. 172 cdp.frq = frq
173 174
175 - def from_xml(self, pipe_node, file_version=None, dir=None):
176 """Read a pipe container XML element and place the contents into this pipe. 177 178 @param pipe_node: The data pipe XML node. 179 @type pipe_node: xml.dom.minidom.Element instance 180 @keyword file_version: The relax XML version of the XML file. 181 @type file_version: int 182 @keyword dir: The name of the directory containing the results file (needed for loading external files). 183 @type dir: str 184 """ 185 186 # Test if empty. 187 if not self.is_empty(): 188 raise RelaxFromXMLNotEmptyError(self.__class__.__name__) 189 190 # Get the global data node, and fill the contents of the pipe. 191 global_node = pipe_node.getElementsByTagName('global')[0] 192 xml_to_object(global_node, self, file_version=file_version) 193 194 # Backwards compatibility transformations. 195 self._back_compat_hook(file_version) 196 197 # Get the hybrid node (and its sub-node), and recreate the hybrid object. 198 hybrid_node = pipe_node.getElementsByTagName('hybrid')[0] 199 pipes_node = hybrid_node.getElementsByTagName('pipes')[0] 200 setattr(self, 'hybrid_pipes', node_value_to_python(pipes_node.childNodes[0])) 201 202 # Get the experimental information data nodes and, if they exist, fill the contents. 203 exp_info_nodes = pipe_node.getElementsByTagName('exp_info') 204 if exp_info_nodes: 205 # Create the data container. 206 self.exp_info = ExpInfo() 207 208 # Fill its contents. 209 self.exp_info.from_xml(exp_info_nodes[0], file_version=file_version) 210 211 # Get the diffusion tensor data nodes and, if they exist, fill the contents. 212 diff_tensor_nodes = pipe_node.getElementsByTagName('diff_tensor') 213 if diff_tensor_nodes: 214 # Create the diffusion tensor object. 215 self.diff_tensor = DiffTensorData() 216 217 # Fill its contents. 218 self.diff_tensor.from_xml(diff_tensor_nodes[0], file_version=file_version) 219 220 # Get the alignment tensor data nodes and, if they exist, fill the contents. 221 align_tensor_nodes = pipe_node.getElementsByTagName('align_tensors') 222 if align_tensor_nodes: 223 # Create the alignment tensor object. 224 self.align_tensors = AlignTensorList() 225 226 # Fill its contents. 227 self.align_tensors.from_xml(align_tensor_nodes[0], file_version=file_version) 228 229 # Recreate the interatomic data structure (this needs to be before the 'mol' structure as the backward compatibility hooks can create interatomic data containers!). 230 interatom_nodes = pipe_node.getElementsByTagName('interatomic') 231 self.interatomic.from_xml(interatom_nodes, file_version=file_version) 232 233 # Recreate the molecule, residue, and spin data structure. 234 mol_nodes = pipe_node.getElementsByTagName('mol') 235 self.mol.from_xml(mol_nodes, file_version=file_version) 236 237 # Get the structural object nodes and, if they exist, fill the contents. 238 str_nodes = pipe_node.getElementsByTagName('structure') 239 if str_nodes: 240 # Get the object type. 241 parser = str(str_nodes[0].getAttribute('id')) 242 243 # Create the structural object. 244 fail = False 245 if parser == 'scientific': 246 self.structure = generic_fns.structure.scientific.Scientific_data() 247 elif parser == 'internal': 248 self.structure = generic_fns.structure.internal.Internal() 249 else: 250 warn(RelaxWarning("The structural file parser " + repr(parser) + " is unknown. The structure will not be loaded.")) 251 fail = True 252 253 # Fill its contents. 254 if not fail: 255 self.structure.from_xml(str_nodes[0], dir=dir, id=parser, file_version=file_version)
256 257
258 - def is_empty(self):
259 """Method for testing if the data pipe is empty. 260 261 @return: True if the data pipe is empty, False otherwise. 262 @rtype: bool 263 """ 264 265 # Is the molecule structure data object empty? 266 if hasattr(self, 'structure'): 267 return False 268 269 # Is the molecule/residue/spin data object empty? 270 if not self.mol.is_empty(): 271 return False 272 273 # Is the interatomic data object empty? 274 if not self.interatomic.is_empty(): 275 return False 276 277 # Tests for the initialised data (the pipe type can be set in an empty data pipe, so this isn't checked). 278 if self.hybrid_pipes: 279 return False 280 281 # An object has been added to the container. 282 for name in dir(self): 283 # Skip the objects initialised in __init__(). 284 if name in ['mol', 'interatomic', 'pipe_type', 'hybrid_pipes']: 285 continue 286 287 # Skip the PipeContainer methods. 288 if name in list(self.__class__.__dict__.keys()): 289 continue 290 291 # Skip special objects. 292 if match("^_", name): 293 continue 294 295 # An object has been added. 296 return False 297 298 # The data pipe is empty. 299 return True
300 301
302 - def to_xml(self, doc, element):
303 """Create a XML element for the current data pipe. 304 305 @param doc: The XML document object. 306 @type doc: xml.dom.minidom.Document instance 307 @param element: The XML element to add the pipe XML element to. 308 @type element: XML element object 309 """ 310 311 # Add all simple python objects within the PipeContainer to the global element. 312 global_element = doc.createElement('global') 313 element.appendChild(global_element) 314 global_element.setAttribute('desc', 'Global data located in the top level of the data pipe') 315 fill_object_contents(doc, global_element, object=self, blacklist=['align_tensors', 'diff_tensor', 'exp_info', 'interatomic', 'hybrid_pipes', 'mol', 'pipe_type', 'structure'] + list(self.__class__.__dict__.keys())) 316 317 # Hybrid info. 318 self.xml_create_hybrid_element(doc, element) 319 320 # Add the experimental information. 321 if hasattr(self, 'exp_info'): 322 self.exp_info.to_xml(doc, element) 323 324 # Add the diffusion tensor data. 325 if hasattr(self, 'diff_tensor'): 326 self.diff_tensor.to_xml(doc, element) 327 328 # Add the alignment tensor data. 329 if hasattr(self, 'align_tensors'): 330 self.align_tensors.to_xml(doc, element) 331 332 # Add the molecule-residue-spin data. 333 self.mol.to_xml(doc, element) 334 335 # Add the interatomic data. 336 self.interatomic.to_xml(doc, element) 337 338 # Add the structural data, if it exists. 339 if hasattr(self, 'structure'): 340 self.structure.to_xml(doc, element)
341 342
343 - def xml_create_hybrid_element(self, doc, element):
344 """Create an XML element for the data pipe hybridisation information. 345 346 @param doc: The XML document object. 347 @type doc: xml.dom.minidom.Document instance 348 @param element: The element to add the hybridisation info to. 349 @type element: XML element object 350 """ 351 352 # Create the hybrid element and add it to the higher level element. 353 hybrid_element = doc.createElement('hybrid') 354 element.appendChild(hybrid_element) 355 356 # Set the hybridisation attributes. 357 hybrid_element.setAttribute('desc', 'Data pipe hybridisation information') 358 359 # Create an element to store the pipes list. 360 list_element = doc.createElement('pipes') 361 hybrid_element.appendChild(list_element) 362 363 # Add the pipes list. 364 text_val = doc.createTextNode(str(self.hybrid_pipes)) 365 list_element.appendChild(text_val)
366