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

Source Code for Module data_store.pipe_container

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