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 selecting and deselecting spins."""
24
25
26 import sys
27 from warnings import warn
28
29
30 from lib.errors import RelaxError, RelaxNoDomainError, RelaxNoSequenceError
31 from lib.selection import Selection, spin_id_to_data_list
32 from lib.sequence import read_spin_data, write_spin_data
33 from lib.warnings import RelaxNoSpinWarning
34 from pipe_control.interatomic import interatomic_loop
35 from pipe_control.mol_res_spin import check_mol_res_spin_data, exists_mol_res_spin_data, generate_spin_id_unique, return_spin, spin_loop
36 from pipe_control.pipes import check_pipe
37 from user_functions.data import Uf_tables; uf_tables = Uf_tables()
38 from user_functions.objects import Desc_container
39
40
41 boolean_doc = Desc_container("Boolean operators")
42 boolean_doc.add_paragraph("The boolean operator can be used to change how spin systems or interatomic data containers are selected. The allowed values are: 'OR', 'NOR', 'AND', 'NAND', 'XOR', 'XNOR'. The following table details how the selections will occur for the different boolean operators.")
43 table = uf_tables.add_table(label="table: bool operators", caption="Boolean operators and their effects on selections")
44 table.add_headings(["Spin system or interatomic data container", "1", "2", "3", "4", "5", "6", "7", "8", "9"])
45 table.add_row(["Original selection", "0", "1", "1", "1", "1", "0", "1", "0", "1"])
46 table.add_row(["New selection", "0", "1", "1", "1", "1", "1", "0", "0", "0"])
47 table.add_row(["OR", "0", "1", "1", "1", "1", "1", "1", "0", "1"])
48 table.add_row(["NOR", "1", "0", "0", "0", "0", "0", "0", "1", "0"])
49 table.add_row(["AND", "0", "1", "1", "1", "1", "0", "0", "0", "0"])
50 table.add_row(["NAND", "1", "0", "0", "0", "0", "1", "1", "1", "1"])
51 table.add_row(["XOR", "0", "0", "0", "0", "0", "1", "1", "0", "1"])
52 table.add_row(["XNOR", "1", "1", "1", "1", "1", "0", "0", "1", "0"])
53 boolean_doc.add_table(table.label)
54
55
57 """Return the new boolean deselection result using the current selection.
58
59 @keyword current: The current selection state.
60 @type current: bool
61 @keyword boolean: The boolean operator used to select with. It can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'.
62 @type boolean: str
63 @return: The new selection state.
64 @rtype: bool
65 """
66
67
68 if boolean == 'OR':
69 state = current or False
70 elif boolean == 'NOR':
71 state = not (current or False)
72 elif boolean == 'AND':
73 state = current and False
74 elif boolean == 'NAND':
75 state = not (current and False)
76 elif boolean == 'XOR':
77 state = not (current and False) and (current or False)
78 elif boolean == 'XNOR':
79 state = (current and False) or not (current or False)
80 else:
81 raise RelaxError("Unknown boolean operator " + repr(boolean))
82
83
84 return state
85
86
88 """Return the new boolean selection result using the current selection.
89
90 @keyword current: The current selection state.
91 @type current: bool
92 @keyword boolean: The boolean operator used to select with. It can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'.
93 @type boolean: str
94 @return: The new selection state.
95 @rtype: bool
96 """
97
98
99 if boolean == 'OR':
100 state = current or True
101 elif boolean == 'NOR':
102 state = not (current or True)
103 elif boolean == 'AND':
104 state = current and True
105 elif boolean == 'NAND':
106 state = not (current and True)
107 elif boolean == 'XOR':
108 state = not (current and True) and (current or True)
109 elif boolean == 'XNOR':
110 state = (current and True) or not (current or True)
111 else:
112 raise RelaxError("Unknown boolean operator " + repr(boolean))
113
114
115 return state
116
117
134
135
136 -def desel_interatom(spin_id1=None, spin_id2=None, boolean='AND', change_all=False):
137 """Deselect specific interatomic data containers.
138
139 @keyword spin_id1: The spin ID string of the first spin of the pair.
140 @type spin_id1: str or None
141 @keyword spin_id2: The spin ID string of the second spin of the pair.
142 @type spin_id2: str or None
143 @param boolean: The boolean operator used to deselect the spin systems with. It can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'. This will be ignored if the change_all flag is set.
144 @type boolean: str
145 @keyword change_all: A flag which if True will cause all spins not specified in the file to be selected. Only the boolean operator 'AND' is compatible with this flag set to True (all others will be ignored).
146 @type change_all: bool
147 @raises RelaxNoSequenceError: If no molecule/residue/spins sequence data exists.
148 @raises RelaxError: If the boolean operator is unknown.
149 """
150
151
152 check_pipe()
153
154
155 if not exists_mol_res_spin_data():
156 raise RelaxNoSequenceError
157
158
159 if change_all:
160
161 for interatom in interatomic_loop(skip_desel=False):
162 interatom.select = True
163
164
165 for interatom in interatomic_loop(selection1=spin_id1, selection2=spin_id2, skip_desel=False):
166
167 if change_all:
168 interatom.select = False
169
170
171 else:
172 interatom.select = boolean_deselect(current=interatom.select, boolean=boolean)
173
174
175 -def desel_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, boolean='AND', change_all=False):
176 """Deselect the spins contained in the given file.
177
178 @keyword file: The name of the file to open.
179 @type file: str
180 @keyword dir: The directory containing the file (defaults to the current
181 directory if None).
182 @type dir: str or None
183 @keyword file_data: An alternative opening a file, if the data already exists in the
184 correct format. The format is a list of lists where the first
185 index corresponds to the row and the second the column.
186 @type file_data: list of lists
187 @keyword spin_id_col: The column containing the spin ID strings. If supplied, the
188 mol_name_col, res_name_col, res_num_col, spin_name_col, and
189 spin_num_col arguments must be none.
190 @type spin_id_col: int or None
191 @keyword mol_name_col: The column containing the molecule name information. If
192 supplied, spin_id_col must be None.
193 @type mol_name_col: int or None
194 @keyword res_name_col: The column containing the residue name information. If
195 supplied, spin_id_col must be None.
196 @type res_name_col: int or None
197 @keyword res_num_col: The column containing the residue number information. If
198 supplied, spin_id_col must be None.
199 @type res_num_col: int or None
200 @keyword spin_name_col: The column containing the spin name information. If supplied,
201 spin_id_col must be None.
202 @type spin_name_col: int or None
203 @keyword spin_num_col: The column containing the spin number information. If supplied,
204 spin_id_col must be None.
205 @type spin_num_col: int or None
206 @keyword sep: The column separator which, if None, defaults to whitespace.
207 @type sep: str or None
208 @keyword spin_id: The spin ID string used to restrict data loading to a subset of
209 all spins.
210 @type spin_id: None or str
211 @param boolean: The boolean operator used to deselect the spin systems with. It
212 can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'.
213 This will be ignored if the change_all flag is set.
214 @type boolean: str
215 @keyword change_all: A flag which if True will cause all spins not specified in the
216 file to be selected. Only the boolean operator 'AND' is
217 compatible with this flag set to True (all others will be
218 ignored).
219 @type change_all: bool
220 @raises RelaxNoSequenceError: If no molecule/residue/spins sequence data exists.
221 @raises RelaxError: If the boolean operator is unknown.
222 """
223
224
225 check_pipe()
226
227
228 if not exists_mol_res_spin_data():
229 raise RelaxNoSequenceError
230
231
232 if change_all:
233 for spin in spin_loop():
234 spin.select = True
235
236
237 ids = []
238 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):
239
240 id = generate_spin_id_unique(mol_name=mol_name, res_num=res_num, res_name=res_name, spin_num=spin_num, spin_name=spin_name)
241 spin = return_spin(id)
242
243
244 if spin == None:
245 warn(RelaxNoSpinWarning(id))
246 continue
247
248
249 if change_all:
250 spin.select = False
251
252
253 else:
254 spin.select = boolean_deselect(current=spin.select, boolean=boolean)
255
256
257 if not spin.select:
258 ids.append(id)
259
260
261 if not len(ids):
262 print("No spins deselected.")
263 else:
264 print("The following spins were deselected:")
265 for id in ids:
266 print(id)
267
268
269 -def desel_spin(spin_id=None, boolean='AND', change_all=False):
270 """Deselect specific spins.
271
272 @keyword spin_id: The spin identification string.
273 @type spin_id: str or None
274 @param boolean: The boolean operator used to deselect the spin systems with. It
275 can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'.
276 This will be ignored if the change_all flag is set.
277 @type boolean: str
278 @keyword change_all: A flag which if True will cause all spins not specified in the
279 file to be selected. Only the boolean operator 'AND' is
280 compatible with this flag set to True (all others will be
281 ignored).
282 @type change_all: bool
283 @raises RelaxNoSequenceError: If no molecule/residue/spins sequence data exists.
284 @raises RelaxError: If the boolean operator is unknown.
285 """
286
287
288 check_pipe()
289
290
291 if not exists_mol_res_spin_data():
292 raise RelaxNoSequenceError
293
294
295 if change_all:
296 for spin in spin_loop():
297 spin.select = True
298
299
300 for spin in spin_loop(spin_id):
301
302 if change_all:
303 spin.select = False
304
305
306 else:
307 spin.select = boolean_deselect(current=spin.select, boolean=boolean)
308
309
310 -def display(sep=None, mol_name_flag=True, res_num_flag=True, res_name_flag=True, spin_num_flag=True, spin_name_flag=True):
311 """Display the current spin selections.
312
313 @keyword sep: The column seperator which, if None, defaults to whitespace.
314 @type sep: str or None
315 @keyword mol_name_flag: A flag which if True will cause the molecule name column to be written.
316 @type mol_name_flag: bool
317 @keyword res_num_flag: A flag which if True will cause the residue number column to be written.
318 @type res_num_flag: bool
319 @keyword res_name_flag: A flag which if True will cause the residue name column to be written.
320 @type res_name_flag: bool
321 @keyword spin_name_flag: A flag which if True will cause the spin name column to be written.
322 @type spin_name_flag: bool
323 @keyword spin_num_flag: A flag which if True will cause the spin number column to be written.
324 @type spin_num_flag: bool
325 """
326
327
328 check_mol_res_spin_data()
329
330
331 mol_names = []
332 res_nums = []
333 res_names = []
334 spin_nums = []
335 spin_names = []
336 selections = []
337
338
339 for spin, mol_name, res_num, res_name in spin_loop(full_info=True, skip_desel=False):
340 mol_names.append(mol_name)
341 res_nums.append(res_num)
342 res_names.append(res_name)
343 spin_nums.append(spin.num)
344 spin_names.append(spin.name)
345 selections.append(spin.select)
346
347
348 if not mol_name_flag:
349 mol_names = None
350 if not res_num_flag:
351 res_nums = None
352 if not res_name_flag:
353 res_names = None
354 if not spin_num_flag:
355 spin_nums = None
356 if not spin_name_flag:
357 spin_names = None
358
359
360 write_spin_data(file=sys.stdout, sep=sep, mol_names=mol_names, res_nums=res_nums, res_names=res_names, spin_nums=spin_nums, spin_names=spin_names, data=selections, data_name="selection")
361
362
364 """Query if the molecule is selected.
365
366 @keyword selection: The molecule ID string.
367 @type selection: str
368 """
369
370
371 select = False
372 for spin in spin_loop(selection):
373 if spin.select:
374 select = True
375 break
376
377
378 return select
379
380
382 """Query if the residue is selected.
383
384 @keyword selection: The residue ID string.
385 @type selection: str
386 """
387
388
389 select = False
390 for spin in spin_loop(selection):
391 if spin.select:
392 select = True
393 break
394
395
396 return select
397
398
400 """Query if the spin is selected.
401
402 @keyword selection: The molecule ID string.
403 @type selection: str
404 """
405
406
407 spin = return_spin(selection)
408
409
410 return spin.select
411
412
435
436
453
454
455 -def sel_domain(domain_id=None, boolean='OR', change_all=False):
456 """Select all spins and interatomic data containers of the given domain.
457
458 @keyword domain_id: The domain ID string.
459 @type domain_id: str or None
460 @param boolean: The boolean operator used to select the spin systems with. It can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'. This will be ignored if the change_all flag is set.
461 @type boolean: str
462 @keyword change_all: A flag which if True will cause all spins and interatomic data containers outside of the domain to be deselected.
463 @type change_all: bool
464 """
465
466
467 check_pipe()
468
469
470 if not hasattr(cdp, 'domain') or domain_id not in cdp.domain:
471 raise RelaxNoDomainError(domain_id)
472
473
474 domain = Selection(cdp.domain[domain_id])
475
476
477 for spin, mol_name, res_num, res_name in spin_loop(full_info=True):
478
479 if domain.contains_spin(spin_name=spin.name, spin_num=spin.num, res_name=res_name, res_num=res_num, mol=mol_name):
480 spin.select = boolean_select(current=spin.select, boolean=boolean)
481
482
483 elif change_all:
484 spin.select = False
485
486
487 for interatom in interatomic_loop():
488
489 mol_name1, res_num1, res_name1, spin_num1, spin_name1 = spin_id_to_data_list(interatom.spin_id1)
490 mol_name2, res_num2, res_name2, spin_num2, spin_name2 = spin_id_to_data_list(interatom.spin_id2)
491
492
493 if domain.contains_spin(spin_name=spin_name1, spin_num=spin_num1, res_name=res_name1, res_num=res_num1, mol=mol_name1) or domain.contains_spin(spin_name=spin_name2, spin_num=spin_num2, res_name=res_name2, res_num=res_num2, mol=mol_name2):
494 interatom.select = boolean_select(current=interatom.select, boolean=boolean)
495
496
497 elif change_all:
498 interatom.select = False
499
500
501 -def sel_interatom(spin_id1=None, spin_id2=None, boolean='OR', change_all=False):
502 """Select specific interatomic data containers.
503
504 @keyword spin_id1: The spin ID string of the first spin of the pair.
505 @type spin_id1: str or None
506 @keyword spin_id2: The spin ID string of the second spin of the pair.
507 @type spin_id2: str or None
508 @param boolean: The boolean operator used to select the spin systems with. It can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'. This will be ignored if the change_all flag is set.
509 @type boolean: str
510 @keyword change_all: A flag which if True will cause all spins not specified in the file to be deselected. Only the boolean operator 'OR' is compatible with this flag set to True (all others will be ignored).
511 @type change_all: bool
512 @raises RelaxNoSequenceError: If no molecule/residue/spins sequence data exists.
513 @raises RelaxError: If the boolean operator is unknown.
514 """
515
516
517 check_pipe()
518
519
520 if not exists_mol_res_spin_data():
521 raise RelaxNoSequenceError
522
523
524 if change_all:
525
526 for interatom in interatomic_loop(skip_desel=False):
527 interatom.select = False
528
529
530 for interatom in interatomic_loop(selection1=spin_id1, selection2=spin_id2, skip_desel=False):
531
532 if change_all:
533 interatom.select = True
534
535
536 else:
537 interatom.select = boolean_select(current=interatom.select, boolean=boolean)
538
539
540 -def sel_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, boolean='OR', change_all=False):
541 """Select the spins contained in the given file.
542
543 @keyword file: The name of the file to open.
544 @type file: str
545 @keyword dir: The directory containing the file (defaults to the current
546 directory if None).
547 @type dir: str or None
548 @keyword file_data: An alternative opening a file, if the data already exists in the
549 correct format. The format is a list of lists where the first
550 index corresponds to the row and the second the column.
551 @type file_data: list of lists
552 @keyword spin_id_col: The column containing the spin ID strings. If supplied, the
553 mol_name_col, res_name_col, res_num_col, spin_name_col, and
554 spin_num_col arguments must be none.
555 @type spin_id_col: int or None
556 @keyword mol_name_col: The column containing the molecule name information. If
557 supplied, spin_id_col must be None.
558 @type mol_name_col: int or None
559 @keyword res_name_col: The column containing the residue name information. If
560 supplied, spin_id_col must be None.
561 @type res_name_col: int or None
562 @keyword res_num_col: The column containing the residue number information. If
563 supplied, spin_id_col must be None.
564 @type res_num_col: int or None
565 @keyword spin_name_col: The column containing the spin name information. If supplied,
566 spin_id_col must be None.
567 @type spin_name_col: int or None
568 @keyword spin_num_col: The column containing the spin number information. If supplied,
569 spin_id_col must be None.
570 @type spin_num_col: int or None
571 @keyword sep: The column separator which, if None, defaults to whitespace.
572 @type sep: str or None
573 @keyword spin_id: The spin ID string used to restrict data loading to a subset of
574 all spins.
575 @type spin_id: None or str
576 @param boolean: The boolean operator used to select the spin systems with. It
577 can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'.
578 This will be ignored if the change_all flag is set.
579 @type boolean: str
580 @keyword change_all: A flag which if True will cause all spins not specified in the
581 file to be deselected. Only the boolean operator 'OR' is
582 compatible with this flag set to True (all others will be
583 ignored).
584 @type change_all: bool
585 @raises RelaxNoSequenceError: If no molecule/residue/spins sequence data exists.
586 @raises RelaxError: If the boolean operator is unknown.
587 """
588
589
590 check_pipe()
591
592
593 if not exists_mol_res_spin_data():
594 raise RelaxNoSequenceError
595
596
597 if change_all:
598
599 for spin in spin_loop():
600 spin.select = False
601
602
603 ids = []
604 for id 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):
605
606 spin = return_spin(id)
607
608
609 if spin == None:
610 warn(RelaxNoSpinWarning(id))
611 continue
612
613
614 if change_all:
615 spin.select = True
616
617
618 else:
619 spin.select = boolean_select(current=spin.select, boolean=boolean)
620
621
622 if spin.select:
623 ids.append(id)
624
625
626 if not len(ids):
627 print("No spins selected.")
628 else:
629 print("The following spins were selected:")
630 for id in ids:
631 print(id)
632
633
634 -def sel_spin(spin_id=None, boolean='OR', change_all=False):
635 """Select specific spins.
636
637 @keyword spin_id: The spin identification string.
638 @type spin_id: str or None
639 @param boolean: The boolean operator used to select the spin systems with. It
640 can be one of 'OR', 'NOR', 'AND', 'NAND', 'XOR', or 'XNOR'.
641 This will be ignored if the change_all flag is set.
642 @type boolean: str
643 @keyword change_all: A flag which if True will cause all spins not specified in the
644 file to be deselected. Only the boolean operator 'OR' is
645 compatible with this flag set to True (all others will be
646 ignored).
647 @type change_all: bool
648 @raises RelaxNoSequenceError: If no molecule/residue/spins sequence data exists.
649 @raises RelaxError: If the boolean operator is unknown.
650 """
651
652
653 check_pipe()
654
655
656 if not exists_mol_res_spin_data():
657 raise RelaxNoSequenceError
658
659
660 if change_all:
661
662 for spin in spin_loop():
663 spin.select = False
664
665
666 for spin in spin_loop(spin_id):
667
668 if change_all:
669 spin.select = True
670
671
672 else:
673 spin.select = boolean_select(current=spin.select, boolean=boolean)
674