1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 """Module for the manipulation of the interatomic data structures in the relax data store."""
24
25
26 from copy import deepcopy
27 from re import search
28 import sys
29
30
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
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
61 pipes.test(pipe_from)
62 pipes.test(pipe_to)
63
64
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
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
83 if not exists_data(pipe_from):
84 return
85
86
87 ids = []
88 for interatom in interatomic_loop(selection1=spin_id1, selection2=spin_id2, pipe=pipe_from):
89
90 new_interatom = create_interatom(spin_id1=interatom.spin_id1, spin_id2=interatom.spin_id2, pipe=pipe_to)
91
92
93 for name in dir(interatom):
94
95 if search('^_', name):
96 continue
97
98
99 if name in ['spin_id1', 'spin_id2']:
100 continue
101
102
103 if name in list(interatom.__class__.__dict__.keys()):
104 continue
105
106
107 obj = deepcopy(getattr(interatom, name))
108 setattr(new_interatom, name, obj)
109
110
111 ids.append([repr(interatom.spin_id1), repr(interatom.spin_id2)])
112
113
114 if verbose:
115 write_data(out=sys.stdout, headings=["Spin_ID_1", "Spin_ID_2"], data=ids)
116
117
147
148
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
163 if pipe == None:
164 pipe = pipes.cdp_name()
165
166
167 dp = pipes.get_pipe(pipe)
168
169
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
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
183 return dp.interatomic.add_item(spin_id1=spin_id1, spin_id2=spin_id2)
184
185
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
196 if pipe == None:
197 pipe = pipes.cdp_name()
198
199
200 pipes.test(pipe)
201
202
203 dp = pipes.get_pipe(pipe)
204
205
206 if dp.interatomic.is_empty():
207 return False
208
209
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
227 spin1 = return_spin(interatom.spin_id1, pipe=pipe)
228 spin2 = return_spin(interatom.spin_id2, pipe=pipe)
229
230
231 if spin1 == None or spin2 == None:
232 return False
233
234
235 if spin_id in spin1._spin_ids or spin_id in spin2._spin_ids:
236 return True
237
238
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
256 if pipe == None:
257 pipe = pipes.cdp_name()
258
259
260 dp = pipes.get_pipe(pipe)
261
262
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
275 for i in range(len(dp.interatomic)):
276
277 if selected and not dp.interatomic[i].select:
278 continue
279
280
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
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
300 yield interatom
301
302
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
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
323 if pipe == None:
324 pipe = pipes.cdp_name()
325
326
327 dp = pipes.get_pipe(pipe)
328
329
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
335 return None
336
337
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
350 if spin_id == None:
351 raise RelaxError("The spin ID must be supplied.")
352
353
354 if pipe == None:
355 pipe = pipes.cdp_name()
356
357
358 dp = pipes.get_pipe(pipe)
359
360
361 interatoms = []
362
363
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
369 return interatoms
370