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

Source Code for Module data_store.interatomic

  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 interatomic data 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 RelaxFromXMLNotEmptyError, RelaxImplementError 
 34  from lib.text.table import format_table 
 35  from lib.xml import fill_object_contents, object_to_xml, xml_to_object 
 36  import specific_analyses 
 37   
 38   
39 -class InteratomContainer(Prototype):
40 """Class containing the interatomic data.""" 41
42 - def __init__(self, spin_id1=None, spin_id2=None, spin_hash1=None, spin_hash2=None, select=True):
43 """Set up the objects of the interatomic data container. 44 45 @keyword spin_id1: The spin ID string of the first atom. 46 @type spin_id1: str 47 @keyword spin_id2: The spin ID string of the second atom. 48 @type spin_id2: str 49 @keyword spin_hash1: The unique and temporary hash identifying the spin container of the first atom. 50 @type spin_hash1: str 51 @keyword spin_hash2: The unique and temporary hash identifying the spin container of the second atom. 52 @type spin_hash2: str 53 @keyword select: The selection flag. 54 @type select: bool 55 """ 56 57 # Store the spin IDs. 58 self.spin_id1 = spin_id1 59 self.spin_id2 = spin_id2 60 self._spin_hash1 = spin_hash1 61 self._spin_hash2 = spin_hash2 62 63 # Class variable defaults. 64 self.dipole_pair = False 65 self.select = select 66 67 # Generate a unique hash for the interatomic data container. 68 self._generate_hash()
69 70
71 - def __repr__(self):
72 """The string representation of the object. 73 74 Rather than using the standard Python conventions (either the string representation of the 75 value or the "<...desc...>" notation), a rich-formatted description of the object is given. 76 """ 77 78 # Intro. 79 text = "Class containing all the interatomic specific data between spins %s and %s.\n\n" % (self.spin_id1, self.spin_id2) 80 81 # Objects. 82 text = text + "\n" 83 text = text + "Objects:\n" 84 for name in dir(self): 85 # Skip the SpinContainer methods. 86 if name in ['is_empty']: 87 continue 88 89 # Skip special objects. 90 if name not in ['_spin_hash1', '_spin_hash2'] and match("^_", name): 91 continue 92 93 # Add the object's attribute to the text string. 94 text += " %s: %s\n" % (name, repr(getattr(self, name))) 95 96 return text
97 98
99 - def _generate_hash(self):
100 """Generate a unique hash for the interatomic data container.""" 101 102 # The hash. 103 self._hash = hexlify(urandom(20))
104 105
106 - def is_empty(self):
107 """Method for testing if this InteratomContainer object is empty. 108 109 @return: True if this container is empty, False otherwise. 110 @rtype: bool 111 """ 112 113 # An object has been added to the container. 114 for name in dir(self): 115 # Skip the objects initialised in __init__(). 116 if name in ['dipole_pair', 'spin_id1', 'spin_id2', 'select']: 117 continue 118 119 # Skip the SpinContainer methods. 120 if name in ['is_empty']: 121 continue 122 123 # Skip special objects. 124 if match("^_", name): 125 continue 126 127 # An object has been added. 128 return False 129 130 # The SpinContainer is unmodified. 131 return True
132 133 134
135 -class InteratomList(list):
136 """List type data container for interatomic specific data.""" 137
138 - def __repr__(self):
139 """The string representation of the object. 140 141 Rather than using the standard Python conventions (either the string representation of the value or the "<...desc...>" notation), a rich-formatted description of the object is given. 142 """ 143 144 # Intro. 145 text = "Interatomic data container list:\n" 146 147 # The data. 148 table = [] 149 for i in range(len(self)): 150 table.append([i, self[i]._hash, self[i].spin_id1, self[i].spin_id2, self[i]._spin_hash1, self[i]._spin_hash2]) 151 text += format_table(headings=[["Index", "Hash", "Spin ID 1", "Spin ID 2", "Spin hash 1", "Spin hash 2"]], contents=table) 152 153 return text
154 155
156 - def add_item(self, spin_id1=None, spin_id2=None, spin_hash1=None, spin_hash2=None):
157 """Append an empty container to the list. 158 159 @keyword spin_id1: The spin ID string of the first atom. 160 @type spin_id1: str 161 @keyword spin_id2: The spin ID string of the second atom. 162 @type spin_id2: str 163 @keyword spin_hash1: The unique and temporary hash identifying the spin container of the first atom. 164 @type spin_hash1: str 165 @keyword spin_hash2: The unique and temporary hash identifying the spin container of the second atom. 166 @type spin_hash2: str 167 @return: The new interatomic data container. 168 @rtype: InteratomContainer instance 169 """ 170 171 # Append a new InteratomContainer. 172 cont = InteratomContainer(spin_id1, spin_id2, spin_hash1, spin_hash2) 173 self.append(cont) 174 175 # Return the container. 176 return cont
177 178
179 - def is_empty(self):
180 """Method for testing if this InteratomList object is empty. 181 182 @return: True if this list contains no InteratomContainers, False otherwise. 183 @rtype: bool 184 """ 185 186 # There are no InteratomContainers. 187 if len(self) == 0: 188 return True 189 190 # Otherwise. 191 return False
192 193
194 - def from_xml(self, interatom_nodes, file_version=None):
195 """Recreate an interatomic list data structure from the XML spin nodes. 196 197 @param interatom_nodes: The spin XML nodes. 198 @type interatom_nodes: xml.dom.minicompat.NodeList instance 199 @keyword file_version: The relax XML version of the XML file. 200 @type file_version: int 201 """ 202 203 # Test if empty. 204 if not self.is_empty(): 205 raise RelaxFromXMLNotEmptyError(self.__class__.__name__) 206 207 # Loop over the containers. 208 for interatom_node in interatom_nodes: 209 # Get the interatomic spin details and add a container to the InteratomList structure. 210 spin_id1 = str(interatom_node.getAttribute('spin_id1')) 211 spin_id2 = str(interatom_node.getAttribute('spin_id2')) 212 self.add_item(spin_id1=spin_id1, spin_id2=spin_id2) 213 214 # Recreate the current container. 215 xml_to_object(interatom_node, self[-1], file_version=file_version)
216 217
218 - def to_xml(self, doc, element, pipe_type=None):
219 """Create XML elements for each spin. 220 221 @param doc: The XML document object. 222 @type doc: xml.dom.minidom.Document instance 223 @param element: The element to add the spin XML elements to. 224 @type element: XML element object 225 @keyword pipe_type: The type of the pipe being converted to XML. 226 @type pipe_type: str 227 """ 228 229 # The specific analysis API object. 230 api = specific_analyses.api.return_api(analysis_type=pipe_type) 231 232 # Loop over the containers. 233 for i in range(len(self)): 234 # Create an XML element for this container and add it to the higher level element. 235 interatom_element = doc.createElement('interatomic') 236 element.appendChild(interatom_element) 237 238 # Set the spin attributes. 239 interatom_element.setAttribute('desc', 'Interatomic data container') 240 interatom_element.setAttribute('spin_id1', str(self[i].spin_id1)) 241 interatom_element.setAttribute('spin_id2', str(self[i].spin_id2)) 242 243 # Get the specific object names and loop over them to get their descriptions. 244 object_info = [] 245 try: 246 for name in api.data_names(error_names=True, sim_names=True): 247 # Get the description. 248 if hasattr(api, 'return_data_desc'): 249 desc = api.return_data_desc(name) 250 else: 251 desc = None 252 253 # Append the two. 254 object_info.append([name, desc]) 255 except RelaxImplementError: 256 pass 257 258 # Add the ordered objects. 259 blacklist = [] 260 for name, desc in object_info: 261 # Add the name to the blacklist. 262 blacklist.append(name) 263 264 # Skip the object if it is missing from the InteratomContainer. 265 if not hasattr(self[i], name): 266 continue 267 268 # Create a new element for this object, and add it to the main element. 269 sub_element = doc.createElement(name) 270 interatom_element.appendChild(sub_element) 271 272 # Add the object description. 273 if desc: 274 sub_element.setAttribute('desc', desc) 275 276 # Get the object. 277 object = getattr(self[i], name) 278 279 # Convert to XML. 280 object_to_xml(doc, sub_element, value=object) 281 282 # Add all simple python objects within the InteratomContainer to the XML element. 283 fill_object_contents(doc, interatom_element, object=self[i], blacklist=['spin_id1', 'spin_id2'] + blacklist + list(self[i].__class__.__dict__.keys()))
284