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