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

Source Code for Module generic_fns.interatomic

  1  ############################################################################### 
  2  #                                                                             # 
  3  # Copyright (C) 2012 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  """Module for the manipulation of the interatomic data structures in the relax data store.""" 
 24   
 25  # Python module imports. 
 26  from copy import deepcopy 
 27  from re import search 
 28  import sys 
 29   
 30  # relax module imports. 
 31  from generic_fns import pipes 
 32  from generic_fns.mol_res_spin import Selection, count_spins, return_spin, spin_loop 
 33  from relax_errors import RelaxError, RelaxInteratomError, RelaxInteratomInconsistentError, RelaxNoInteratomError, RelaxNoSpinError 
 34  from relax_io import write_data 
 35   
 36   
37 -def copy(pipe_from=None, pipe_to=None, spin_id1=None, spin_id2=None, verbose=True):
38 """Copy the interatomic data from one data pipe to another. 39 40 @keyword pipe_from: The data pipe to copy the interatomic data from. This defaults to the current data pipe. 41 @type pipe_from: str 42 @keyword pipe_to: The data pipe to copy the interatomic data to. This defaults to the current data pipe. 43 @type pipe_to: str 44 @keyword spin_id1: The spin ID string of the first atom. 45 @type spin_id1: str 46 @keyword spin_id2: The spin ID string of the second atom. 47 @type spin_id2: str 48 @keyword verbose: A flag which if True will cause info about each spin pair to be printed out. 49 @type verbose: bool 50 """ 51 52 # Defaults. 53 if pipe_from == None and pipe_to == None: 54 raise RelaxError("The pipe_from and pipe_to arguments cannot both be set to None.") 55 elif pipe_from == None: 56 pipe_from = pipes.cdp_name() 57 elif pipe_to == None: 58 pipe_to = pipes.cdp_name() 59 60 # Test if the pipe_from and pipe_to data pipes exist. 61 pipes.test(pipe_from) 62 pipes.test(pipe_to) 63 64 # Check that the spin IDs exist. 65 if spin_id1: 66 if count_spins(selection=spin_id1, pipe=pipe_from, skip_desel=False) == 0: 67 raise RelaxNoSpinError(spin_id1, pipe_from) 68 if count_spins(selection=spin_id1, pipe=pipe_to, skip_desel=False) == 0: 69 raise RelaxNoSpinError(spin_id1, pipe_to) 70 if spin_id2: 71 if count_spins(selection=spin_id2, pipe=pipe_from, skip_desel=False) == 0: 72 raise RelaxNoSpinError(spin_id2, pipe_from) 73 if count_spins(selection=spin_id2, pipe=pipe_to, skip_desel=False) == 0: 74 raise RelaxNoSpinError(spin_id2, pipe_to) 75 76 # Check for the sequence data in the target pipe if no spin IDs are given. 77 if not spin_id1 and not spin_id2: 78 for spin, spin_id in spin_loop(pipe=pipe_from, return_id=True): 79 if not return_spin(spin_id, pipe=pipe_to): 80 raise RelaxNoSpinError(spin_id, pipe_to) 81 82 # Test if pipe_from contains interatomic data (skipping the rest of the function if it is missing). 83 if not exists_data(pipe_from): 84 return 85 86 # Loop over the interatomic data of the pipe_from data pipe. 87 ids = [] 88 for interatom in interatomic_loop(selection1=spin_id1, selection2=spin_id2, pipe=pipe_from): 89 # Create a new container. 90 new_interatom = create_interatom(spin_id1=interatom.spin_id1, spin_id2=interatom.spin_id2, pipe=pipe_to) 91 92 # Duplicate all the objects of the container. 93 for name in dir(interatom): 94 # Skip special objects. 95 if search('^_', name): 96 continue 97 98 # Skip the spin IDs. 99 if name in ['spin_id1', 'spin_id2']: 100 continue 101 102 # Skip class methods. 103 if name in list(interatom.__class__.__dict__.keys()): 104 continue 105 106 # Duplicate all other objects. 107 obj = deepcopy(getattr(interatom, name)) 108 setattr(new_interatom, name, obj) 109 110 # Store the IDs for the printout. 111 ids.append([repr(interatom.spin_id1), repr(interatom.spin_id2)]) 112 113 # Print out. 114 if verbose: 115 write_data(out=sys.stdout, headings=["Spin_ID_1", "Spin_ID_2"], data=ids)
116 117
118 -def consistent_interatomic_data(pipe1=None, pipe2=None):
119 """Check that the interatomic data is consistent between two data pipes. 120 121 @keyword pipe1: The name of the first data pipe to compare. 122 @type pipe1: str 123 @keyword pipe2: The name of the second data pipe to compare. 124 @type pipe2: str 125 @raises RelaxError: If the data is inconsistent. 126 """ 127 128 # Get the data pipes. 129 dp1 = pipes.get_pipe(pipe1) 130 dp2 = pipes.get_pipe(pipe2) 131 132 # Check the data lengths. 133 if len(dp1.interatomic) != len(dp2.interatomic): 134 raise RelaxInteratomInconsistentError(pipe1, pipe2) 135 136 # Loop over the interatomic data. 137 for i in range(len(dp1.interatomic)): 138 # Alias the containers. 139 interatom1 = dp1.interatomic[i] 140 interatom2 = dp2.interatomic[i] 141 142 # Check the spin IDs. 143 if interatom1.spin_id1 != interatom2.spin_id1: 144 raise RelaxInteratomInconsistentError(pipe1, pipe2) 145 if interatom1.spin_id2 != interatom2.spin_id2: 146 raise RelaxInteratomInconsistentError(pipe1, pipe2)
147 148
149 -def create_interatom(spin_id1=None, spin_id2=None, pipe=None):
150 """Create and return the interatomic data container for the two spins. 151 152 @keyword spin_id1: The spin ID string of the first atom. 153 @type spin_id1: str 154 @keyword spin_id2: The spin ID string of the second atom. 155 @type spin_id2: str 156 @keyword pipe: The data pipe to create the interatomic data container for. This defaults to the current data pipe if not supplied. 157 @type pipe: str or None 158 @return: The newly created interatomic data container. 159 @rtype: data.interatomic.InteratomContainer instance 160 """ 161 162 # The data pipe. 163 if pipe == None: 164 pipe = pipes.cdp_name() 165 166 # Get the data pipe. 167 dp = pipes.get_pipe(pipe) 168 169 # Check that the spin IDs exist. 170 spin = return_spin(spin_id1, pipe) 171 if spin == None: 172 raise RelaxNoSpinError(spin_id1) 173 spin = return_spin(spin_id2, pipe) 174 if spin == None: 175 raise RelaxNoSpinError(spin_id2) 176 177 # Check if the two spin IDs have already been added. 178 for i in range(len(dp.interatomic)): 179 if id_match(spin_id=spin_id1, interatom=dp.interatomic[i], pipe=pipe) and id_match(spin_id=spin_id2, interatom=dp.interatomic[i], pipe=pipe): 180 raise RelaxError("The spin pair %s and %s have already been added." % (spin_id1, spin_id2)) 181 182 # Add and return the data. 183 return dp.interatomic.add_item(spin_id1=spin_id1, spin_id2=spin_id2)
184 185
186 -def exists_data(pipe=None):
187 """Determine if any interatomic data exists. 188 189 @keyword pipe: The data pipe in which the interatomic data will be checked for. 190 @type pipe: str 191 @return: The answer to the question about the existence of data. 192 @rtype: bool 193 """ 194 195 # The current data pipe. 196 if pipe == None: 197 pipe = pipes.cdp_name() 198 199 # Test the data pipe. 200 pipes.test(pipe) 201 202 # Get the data pipe. 203 dp = pipes.get_pipe(pipe) 204 205 # The interatomic data structure is empty. 206 if dp.interatomic.is_empty(): 207 return False 208 209 # Otherwise. 210 return True
211 212
213 -def id_match(spin_id=None, interatom=None, pipe=None):
214 """Test if the spin ID matches one of the two spins of the given container. 215 216 @keyword spin_id: The spin ID string of the first atom. 217 @type spin_id: str 218 @keyword interatom: The interatomic data container. 219 @type interatom: InteratomContainer instance 220 @keyword pipe: The data pipe containing the interatomic data container. Defaults to the current data pipe. 221 @type pipe: str or None 222 @return: True if the spin ID matches one of the two spins, False otherwise. 223 @rtype: bool 224 """ 225 226 # Get the spin containers. 227 spin1 = return_spin(interatom.spin_id1, pipe=pipe) 228 spin2 = return_spin(interatom.spin_id2, pipe=pipe) 229 230 # No spins. 231 if spin1 == None or spin2 == None: 232 return False 233 234 # Check if the ID is in the private metadata list. 235 if spin_id in spin1._spin_ids or spin_id in spin2._spin_ids: 236 return True 237 238 # Nothing found. 239 return False
240 241
242 -def interatomic_loop(selection1=None, selection2=None, pipe=None, selected=True):
243 """Generator function for looping over all the interatomic data containers. 244 245 @keyword selection1: The optional spin ID selection of the first atom. 246 @type selection1: str 247 @keyword selection2: The optional spin ID selection of the second atom. 248 @type selection2: str 249 @keyword pipe: The data pipe containing the spin. Defaults to the current data pipe. 250 @type pipe: str 251 @keyword selected: A flag which if True will only return selected interatomic data containers. 252 @type selected: bool 253 """ 254 255 # The data pipe. 256 if pipe == None: 257 pipe = pipes.cdp_name() 258 259 # Get the data pipe. 260 dp = pipes.get_pipe(pipe) 261 262 # Parse the spin ID selection strings. 263 select_obj = None 264 select_obj1 = None 265 select_obj2 = None 266 if selection1 and selection2: 267 select_obj1 = Selection(selection1) 268 select_obj2 = Selection(selection2) 269 elif selection1: 270 select_obj = Selection(selection1) 271 elif selection2: 272 select_obj = Selection(selection2) 273 274 # Loop over the containers, yielding them. 275 for i in range(len(dp.interatomic)): 276 # Skip deselected containers. 277 if selected and not dp.interatomic[i].select: 278 continue 279 280 # Aliases. 281 interatom = dp.interatomic[i] 282 mol_index1, res_index1, spin_index1 = cdp.mol._spin_id_lookup[interatom.spin_id1] 283 mol_index2, res_index2, spin_index2 = cdp.mol._spin_id_lookup[interatom.spin_id2] 284 mol1 = cdp.mol[mol_index1] 285 res1 = cdp.mol[mol_index1].res[res_index1] 286 spin1 = cdp.mol[mol_index1].res[res_index1].spin[spin_index1] 287 mol2 = cdp.mol[mol_index2] 288 res2 = cdp.mol[mol_index2].res[res_index2] 289 spin2 = cdp.mol[mol_index2].res[res_index2].spin[spin_index2] 290 291 # Check that the selections are met. 292 if select_obj: 293 if (mol1, res1, spin1) not in select_obj and (mol2, res2, spin2) not in select_obj: 294 continue 295 if select_obj1: 296 if not ((mol1, res1, spin1) in select_obj1 or (mol2, res2, spin2) in select_obj1) or not ((mol1, res1, spin1) in select_obj2 or (mol2, res2, spin2) in select_obj2): 297 continue 298 299 # Return the container. 300 yield interatom
301 302
303 -def return_interatom(spin_id1=None, spin_id2=None, pipe=None):
304 """Return the list of interatomic data containers for the two spins. 305 306 @keyword spin_id1: The spin ID string of the first atom. 307 @type spin_id1: str 308 @keyword spin_id2: The spin ID string of the second atom. 309 @type spin_id2: str 310 @keyword pipe: The data pipe holding the container. Defaults to the current data pipe. 311 @type pipe: str or None 312 @return: The matching interatomic data container, if it exists. 313 @rtype: data.interatomic.InteratomContainer instance or None 314 """ 315 316 # Checks. 317 if spin_id1 == None: 318 raise RelaxError("The first spin ID must be supplied.") 319 if spin_id2 == None: 320 raise RelaxError("The second spin ID must be supplied.") 321 322 # The data pipe. 323 if pipe == None: 324 pipe = pipes.cdp_name() 325 326 # Get the data pipe. 327 dp = pipes.get_pipe(pipe) 328 329 # Return the matching container. 330 for i in range(len(dp.interatomic)): 331 if id_match(spin_id=spin_id1, interatom=dp.interatomic[i], pipe=pipe) and id_match(spin_id=spin_id2, interatom=dp.interatomic[i], pipe=pipe): 332 return dp.interatomic[i] 333 334 # No matchs. 335 return None
336 337
338 -def return_interatom_list(spin_id=None, pipe=None):
339 """Return the list of interatomic data containers for the given spin. 340 341 @keyword spin_id: The spin ID string. 342 @type spin_id: str 343 @keyword pipe: The data pipe holding the container. This defaults to the current data pipe. 344 @type pipe: str or None 345 @return: The list of matching interatomic data containers, if any exist. 346 @rtype: list of data.interatomic.InteratomContainer instances 347 """ 348 349 # Check. 350 if spin_id == None: 351 raise RelaxError("The spin ID must be supplied.") 352 353 # The data pipe. 354 if pipe == None: 355 pipe = pipes.cdp_name() 356 357 # Get the data pipe. 358 dp = pipes.get_pipe(pipe) 359 360 # Initialise. 361 interatoms = [] 362 363 # Find and append all containers. 364 for i in range(len(dp.interatomic)): 365 if id_match(spin_id=spin_id, interatom=dp.interatomic[i], pipe=pipe) or id_match(spin_id=spin_id, interatom=dp.interatomic[i], pipe=pipe): 366 interatoms.append(dp.interatomic[i]) 367 368 # Return the list of containers. 369 return interatoms
370