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 handling the molecule, residue, and spin sequence."""
24
25
26 from copy import deepcopy
27 from re import search
28 import sys
29
30
31 from lib.arg_check import is_int
32 from lib.errors import RelaxError, RelaxDiffMolNumError, RelaxDiffResNumError, RelaxDiffSeqError, RelaxDiffSpinNumError, RelaxInvalidSeqError, RelaxNoSequenceError, RelaxSequenceError
33 from lib.io import read_spin_data, write_spin_data
34 from pipe_control import pipes
35 from pipe_control.interatomic import return_interatom_list
36 from pipe_control.mol_res_spin import count_molecules, count_residues, count_spins, create_molecule, create_residue, create_spin, exists_mol_res_spin_data, generate_spin_id, return_molecule, return_residue, return_spin, set_spin_element, set_spin_isotope, spin_loop
37
38
39
41 """Attach a single proton to all heteronuclei."""
42
43
44 mol_names = []
45 res_nums = []
46 res_names = []
47 for spin, mol_name, res_num, res_name, spin_id in spin_loop(full_info=True, return_id=True):
48
49 if hasattr(spin, 'element') and spin.element == 'H':
50 continue
51
52
53 interatoms = return_interatom_list(spin_id)
54 proton_found = False
55 if len(interatoms):
56 for i in range(len(interatoms)):
57
58 spin_attached = return_spin(interatoms[i].spin_id1)
59 if id(spin_attached) == id(spin):
60 spin_attached = return_spin(interatoms[i].spin_id2)
61
62
63 if hasattr(spin_attached, 'element') and spin_attached.element == 'H' or spin.name == 'H':
64 proton_found = True
65 break
66
67
68 if proton_found:
69 continue
70
71
72 mol_names.append(mol_name)
73 res_nums.append(res_num)
74 res_names.append(res_name)
75
76
77 for i in range(len(mol_names)):
78
79 create_spin(spin_name='H', res_name=res_names[i], res_num=res_nums[i], mol_name=mol_names[i])
80
81
82 set_spin_element(spin_id='@H', element='H')
83 set_spin_isotope(spin_id='@H', isotope='1H')
84
85
86 -def copy(pipe_from=None, pipe_to=None, preserve_select=False, empty=True, verbose=True):
87 """Copy the molecule, residue, and spin sequence data from one data pipe to another.
88
89 @keyword pipe_from: The data pipe to copy the sequence data from. This defaults to the current data pipe.
90 @type pipe_from: str
91 @keyword pipe_to: The data pipe to copy the sequence data to. This defaults to the current data pipe.
92 @type pipe_to: str
93 @keyword preserve_select: A flag which if True will cause spin selections to be preserved.
94 @type preserve_select: bool
95 @keyword empty: A flag which if True will create a molecule, residue, and spin sequence in the target pipe lacking all of the spin data of the source pipe. If False, then the spin data will also be copied.
96 @keyword verbose: A flag which if True will cause info about each spin to be printed out as the sequence is generated.
97 @type verbose: bool
98 """
99
100
101 if pipe_from == None and pipe_to == None:
102 raise RelaxError("The pipe_from and pipe_to arguments cannot both be set to None.")
103 elif pipe_from == None:
104 pipe_from = pipes.cdp_name()
105 elif pipe_to == None:
106 pipe_to = pipes.cdp_name()
107
108
109 pipes.test(pipe_from)
110 pipes.test(pipe_to)
111
112
113 if not exists_mol_res_spin_data(pipe_from):
114 raise RelaxNoSequenceError
115
116
117 if exists_mol_res_spin_data(pipe_to):
118 raise RelaxSequenceError
119
120
121 for spin, mol_name, res_num, res_name in spin_loop(pipe=pipe_from, full_info=True):
122
123 new_spin = create_spin(spin_num=spin.num, spin_name=spin.name, res_num=res_num, res_name=res_name, mol_name=mol_name, pipe=pipe_to)
124
125
126 if preserve_select:
127 new_spin.select = spin.select
128 else:
129 select = True
130
131
132 if not empty:
133
134 for name in dir(spin):
135
136 if search('^_', name):
137 continue
138
139
140
141
142
143
144 if name in list(spin.__class__.__dict__.keys()):
145 continue
146
147
148 obj = deepcopy(getattr(spin, name))
149 setattr(new_spin, name, obj)
150
151
152 if verbose:
153 display(mol_name_flag=True, res_num_flag=True, res_name_flag=True, spin_num_flag=True, spin_name_flag=True)
154
155
207
208
209 -def display(sep=None, mol_name_flag=False, res_num_flag=False, res_name_flag=False, spin_num_flag=False, spin_name_flag=False):
210 """Display the molecule, residue, and/or spin sequence data.
211
212 This calls the write() function to do most of the work.
213
214
215 @keyword sep: The column seperator which, if None, defaults to whitespace.
216 @type sep: str or None
217 @keyword mol_name_flag: A flag which if True will cause the molecule name column to be
218 written.
219 @type mol_name_flag: bool
220 @keyword res_num_flag: A flag which if True will cause the residue number column to be
221 written.
222 @type res_num_flag: bool
223 @keyword res_name_flag: A flag which if True will cause the residue name column to be
224 written.
225 @type res_name_flag: bool
226 @keyword spin_name_flag: A flag which if True will cause the spin name column to be written.
227 @type spin_name_flag: bool
228 @keyword spin_num_flag: A flag which if True will cause the spin number column to be
229 written.
230 @type spin_num_flag: bool
231 @param mol_name_flag: The column to contain the molecule name information.
232 """
233
234
235 if not count_spins():
236 raise RelaxNoSequenceError
237
238
239 write(file=sys.stdout, sep=sep, mol_name_flag=mol_name_flag, res_num_flag=res_num_flag, res_name_flag=res_name_flag, spin_num_flag=spin_num_flag, spin_name_flag=spin_name_flag)
240
241
242 -def generate(mol_name=None, res_num=None, res_name=None, spin_num=None, spin_name=None, pipe=None, select=True, verbose=True):
243 """Generate the sequence item-by-item by adding a single molecule/residue/spin container as necessary.
244
245 @keyword mol_name: The molecule name.
246 @type mol_name: str or None
247 @keyword res_num: The residue number.
248 @type res_num: int or None
249 @keyword res_name: The residue name.
250 @type res_name: str or None
251 @keyword spin_num: The spin number.
252 @type spin_num: int or None
253 @keyword spin_name: The spin name.
254 @type spin_name: str or None
255 @keyword pipe: The data pipe in which to generate the sequence. This defaults to the current data pipe.
256 @type pipe: str
257 @keyword select: The spin selection flag.
258 @type select: bool
259 @keyword verbose: A flag which if True will cause info about each spin to be printed out as the sequence is generated.
260 @type verbose: bool
261 """
262
263
264 if pipe == None:
265 pipe = pipes.cdp_name()
266
267
268 if not return_molecule(generate_spin_id(mol_name=mol_name), pipe=pipe):
269 create_molecule(mol_name=mol_name, pipe=pipe)
270
271
272 curr_res = return_residue(generate_spin_id(mol_name=mol_name, res_num=res_num, res_name=res_name), pipe=pipe)
273 if not curr_res or ((res_num != None and curr_res.num != res_num) or (res_name != None and curr_res.name != res_name)):
274 create_residue(mol_name=mol_name, res_num=res_num, res_name=res_name, pipe=pipe)
275
276
277 curr_spin = return_spin(generate_spin_id(mol_name=mol_name, res_num=res_num, res_name=res_name, spin_num=spin_num, spin_name=spin_name), pipe=pipe)
278 if not curr_spin or ((spin_num != None and curr_spin.num != spin_num) or (spin_name != None and curr_spin.name != spin_name)):
279
280 curr_spin = create_spin(mol_name=mol_name, res_num=res_num, res_name=res_name, spin_num=spin_num, spin_name=spin_name, pipe=pipe)
281
282
283 curr_spin.select = select
284
285
286 -def read(file=None, dir=None, file_data=None, spin_id_col=None, mol_name_col=None, res_num_col=None, res_name_col=None, spin_num_col=None, spin_name_col=None, sep=None, spin_id=None):
287 """Read the molecule, residue, and/or spin sequence data from file.
288
289 @param file: The name of the file to open.
290 @type file: str
291 @param dir: The directory containing the file (defaults to the current directory if
292 None).
293 @type dir: str or None
294 @keyword file_data: An alternative to opening a file, if the data already exists in the
295 correct format. The format is a list of lists where the first index
296 corresponds to the row and the second the column.
297 @type file_data: list of lists
298 @keyword spin_id_col: The column containing the spin ID strings. If supplied, the
299 mol_name_col, res_name_col, res_num_col, spin_name_col, and spin_num_col
300 arguments must be none.
301 @type spin_id_col: int or None
302 @keyword mol_name_col: The column containing the molecule name information. If supplied,
303 spin_id_col must be None.
304 @type mol_name_col: int or None
305 @keyword res_name_col: The column containing the residue name information. If supplied,
306 spin_id_col must be None.
307 @type res_name_col: int or None
308 @keyword res_num_col: The column containing the residue number information. If supplied,
309 spin_id_col must be None.
310 @type res_num_col: int or None
311 @keyword spin_name_col: The column containing the spin name information. If supplied,
312 spin_id_col must be None.
313 @type spin_name_col: int or None
314 @keyword spin_num_col: The column containing the spin number information. If supplied,
315 spin_id_col must be None.
316 @type spin_num_col: int or None
317 @keyword sep: The column separator which, if None, defaults to whitespace.
318 @type sep: str or None
319 @keyword spin_id: The spin ID string used to restrict data loading to a subset of all
320 spins.
321 @type spin_id: None or str
322 """
323
324
325 pipes.test()
326
327
328 if exists_mol_res_spin_data():
329 raise RelaxSequenceError
330
331
332 mol_names = []
333 res_nums = []
334 res_names = []
335 spin_nums = []
336 spin_names = []
337
338
339 for mol_name, res_num, res_name, spin_num, spin_name in read_spin_data(file=file, dir=dir, file_data=file_data, spin_id_col=spin_id_col, mol_name_col=mol_name_col, res_num_col=res_num_col, res_name_col=res_name_col, spin_num_col=spin_num_col, spin_name_col=spin_name_col, sep=sep, spin_id=spin_id):
340
341 generate(mol_name=mol_name, res_num=res_num, res_name=res_name, spin_num=spin_num, spin_name=spin_name)
342
343
344 mol_names.append(mol_name)
345 res_nums.append(res_num)
346 res_names.append(res_name)
347 spin_nums.append(spin_num)
348 spin_names.append(spin_name)
349
350
351 if not len(spin_names):
352 raise RelaxError("No sequence data could be loaded.")
353
354
355 write_spin_data(sys.stdout, mol_names=mol_names, res_nums=res_nums, res_names=res_names, spin_nums=spin_nums, spin_names=spin_names)
356
357
359 """Return a list of all proton spin containers attached to the given spin.
360
361 @keyword spin_id: The spin ID string.
362 @type spin_id: str
363 @return: The list of proton spin containers attached to the given spin.
364 @rtype: list of SpinContainer instances
365 """
366
367
368 spin_list = []
369
370
371 interatoms = return_interatom_list(spin_id)
372
373
374 if not len(interatoms):
375 return spin_list
376
377
378 for i in range(len(interatoms)):
379
380 if interatoms[i].spin_id1 == spin_id:
381 attached = return_spin(interatoms[i].spin_id2)
382 else:
383 attached = return_spin(interatoms[i].spin_id1)
384
385
386 if (hasattr(attached, 'element') and attached.element == 'H') or attached.name == 'H':
387 spin_list.append(attached)
388
389
390 return spin_list
391
392
393 -def validate_sequence(data, spin_id_col=None, mol_name_col=None, res_num_col=None, res_name_col=None, spin_num_col=None, spin_name_col=None, data_col=None, error_col=None):
394 """Test if the sequence data is valid.
395
396 The only function this performs is to raise a RelaxError if the data is invalid.
397
398
399 @param data: The sequence data.
400 @type data: list of lists.
401 @keyword spin_id_col: The column containing the spin ID strings.
402 @type spin_id_col: int or None
403 @param mol_name_col: The column containing the molecule name information.
404 @type mol_name_col: int or None
405 @param res_name_col: The column containing the residue name information.
406 @type res_name_col: int or None
407 @param res_num_col: The column containing the residue number information.
408 @type res_num_col: int or None
409 @param spin_name_col: The column containing the spin name information.
410 @type spin_name_col: int or None
411 @param spin_num_col: The column containing the spin number information.
412 @type spin_num_col: int or None
413 """
414
415
416 if spin_id_col:
417 if len(data) < spin_id_col:
418 raise RelaxInvalidSeqError(data, "the Spin ID data is missing")
419
420
421 if mol_name_col:
422 if len(data) < mol_name_col:
423 raise RelaxInvalidSeqError(data, "the molecule name data is missing")
424
425
426 if res_num_col:
427
428 if len(data) < res_num_col:
429 raise RelaxInvalidSeqError(data, "the residue number data is missing")
430
431
432 try:
433 res_num = eval(data[res_num_col-1])
434 if not (res_num == None or is_int(res_num, raise_error=False)):
435 raise ValueError
436 except:
437 raise RelaxInvalidSeqError(data, "the residue number data '%s' is invalid" % data[res_num_col-1])
438
439
440 if res_name_col:
441 if len(data) < res_name_col:
442 raise RelaxInvalidSeqError(data, "the residue name data is missing")
443
444
445 if spin_num_col:
446
447 if len(data) < spin_num_col:
448 raise RelaxInvalidSeqError(data, "the spin number data is missing")
449
450
451 try:
452 res_num = eval(data[res_num_col-1])
453 if not (res_num == None or is_int(res_num, raise_error=False)):
454 raise ValueError
455 except:
456 raise RelaxInvalidSeqError(data, "the spin number data '%s' is invalid" % data[res_num_col-1])
457
458
459 if spin_name_col:
460 if len(data) < spin_name_col:
461 raise RelaxInvalidSeqError(data, "the spin name data is missing")
462
463
464 if data_col:
465 if len(data) < data_col:
466 raise RelaxInvalidSeqError(data, "the data is missing")
467
468
469 if error_col:
470 if len(data) < error_col:
471 raise RelaxInvalidSeqError(data, "the error data is missing")
472
473
474 -def write(file, dir=None, sep=None, mol_name_flag=True, res_num_flag=True, res_name_flag=True, spin_num_flag=True, spin_name_flag=True, force=False):
475 """Write the molecule, residue, and/or sequence data.
476
477 This calls the lib.io.write_spin_data() function to do most of the work.
478
479
480 @param file: The name of the file to write the data to.
481 @type file: str
482 @keyword dir: The directory to contain the file (defaults to the current directory if None).
483 @type dir: str or None
484 @keyword sep: The column seperator which, if None, defaults to whitespace.
485 @type sep: str or None
486 @keyword mol_name_flag: A flag which if True will cause the molecule name column to be written.
487 @type mol_name_flag: bool
488 @keyword res_num_flag: A flag which if True will cause the residue number column to be written.
489 @type res_num_flag: bool
490 @keyword res_name_flag: A flag which if True will cause the residue name column to be written.
491 @type res_name_flag: bool
492 @keyword spin_name_flag: A flag which if True will cause the spin name column to be written.
493 @type spin_name_flag: bool
494 @keyword spin_num_flag: A flag which if True will cause the spin number column to be written.
495 @keyword force: A flag which if True will cause an existing file to be overwritten.
496 @type force: bin
497 """
498
499
500 if not count_spins():
501 raise RelaxNoSequenceError
502
503
504 mol_names = []
505 res_nums = []
506 res_names = []
507 spin_nums = []
508 spin_names = []
509
510
511 for spin, mol_name, res_num, res_name in spin_loop(full_info=True):
512 mol_names.append(mol_name)
513 res_nums.append(res_num)
514 res_names.append(res_name)
515 spin_nums.append(spin.num)
516 spin_names.append(spin.name)
517
518
519 if not mol_name_flag:
520 mol_names = None
521 if not res_num_flag:
522 res_nums = None
523 if not res_name_flag:
524 res_names = None
525 if not spin_num_flag:
526 spin_nums = None
527 if not spin_name_flag:
528 spin_names = None
529
530
531 write_spin_data(file=file, dir=dir, sep=sep, mol_names=mol_names, res_nums=res_nums, res_names=res_names, spin_nums=spin_nums, spin_names=spin_names, force=force)
532